MeshiTrack/packages/api/tests/modules/stores/stores.repository.test.ts

176 lines
5 KiB
TypeScript
Raw Normal View History

import { describe, it, expect, vi, beforeEach } from 'vitest';
const { mockFind, mockFindOne, mockFindOneAndUpdate, mockSave } = vi.hoisted(() => ({
mockFind: vi.fn(),
mockFindOne: vi.fn(),
mockFindOneAndUpdate: vi.fn(),
mockSave: vi.fn(),
}));
2026-05-19 11:06:03 +09:00
vi.mock('../../../src/schemas/store.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 = () => ({ exec: mockFindOneAndUpdate });
class FakeModel {
data: unknown;
2026-04-26 18:44:59 +09:00
constructor(data: unknown) {
this.data = data;
}
save = mockSave;
2026-04-26 18:44:59 +09:00
toObject() {
return this.data;
}
static find = vi.fn(() => chain());
static findOne = vi.fn(() => findOneChain());
static findOneAndUpdate = vi.fn(() => updateChain());
}
return { StoreModel: FakeModel };
});
2026-05-19 11:06:03 +09:00
import { StoresRepository } from '../../../src/modules/stores/stores.repository.js';
describe(StoresRepository.name, () => {
let repo: StoresRepository;
beforeEach(() => {
vi.clearAllMocks();
repo = new StoresRepository();
});
describe('findByHousehold', () => {
it('returns paginated items', async () => {
const items = [{ _id: 'st-1', name: 'Walgreens' }];
mockFind.mockResolvedValue(items);
const result = await repo.findByHousehold('hh1', { limit: 20 });
expect(result.data).toEqual(items);
expect(result.pagination.hasMore).toBe(false);
expect(result.pagination.cursor).toBeNull();
});
it('sets hasMore when more items exist', async () => {
const items = [{ _id: 'st-1' }, { _id: 'st-2' }, { _id: 'st-3' }];
mockFind.mockResolvedValue(items);
const result = await repo.findByHousehold('hh1', { limit: 2 });
expect(result.data).toHaveLength(2);
expect(result.pagination.hasMore).toBe(true);
expect(result.pagination.cursor).toBeTruthy();
});
it('handles cursor pagination', async () => {
mockFind.mockResolvedValue([]);
const cursor = Buffer.from('st-1').toString('base64');
const result = await repo.findByHousehold('hh1', { cursor, limit: 20 });
expect(result.pagination.hasMore).toBe(false);
});
it('filters by tags', async () => {
mockFind.mockResolvedValue([]);
await repo.findByHousehold('hh1', { tags: 'pharmacy,online', limit: 20 });
expect(mockFind).toHaveBeenCalled();
});
it('filters by search', async () => {
mockFind.mockResolvedValue([]);
await repo.findByHousehold('hh1', { search: 'cvs', limit: 20 });
expect(mockFind).toHaveBeenCalled();
});
it('skips tag filter when tags string is empty after trim', async () => {
mockFind.mockResolvedValue([]);
await repo.findByHousehold('hh1', { tags: ' , ', limit: 20 });
expect(mockFind).toHaveBeenCalled();
});
it('returns null cursor when no data', async () => {
mockFind.mockResolvedValue([]);
const result = await repo.findByHousehold('hh1', { limit: 20 });
expect(result.pagination.cursor).toBeNull();
});
});
describe('findById', () => {
it('returns store when found', async () => {
const store = { _id: 'st-1', name: 'CVS' };
mockFindOne.mockResolvedValue(store);
const result = await repo.findById('st-1', 'hh1');
expect(result).toEqual(store);
});
it('returns null when not found', async () => {
mockFindOne.mockResolvedValue(null);
expect(await repo.findById('missing', 'hh1')).toBeNull();
});
});
describe('create', () => {
it('creates and returns store', async () => {
const data = { name: 'Walgreens', tags: [], isActive: true };
mockSave.mockImplementation(function (this: { toObject: () => unknown }) {
return Promise.resolve(this);
});
const result = await repo.create(data as never, 'hh1', 'user-1');
expect(result).toBeTruthy();
expect(mockSave).toHaveBeenCalled();
});
});
describe('update', () => {
it('updates and returns store', async () => {
const updated = { _id: 'st-1', name: 'Updated' };
mockFindOneAndUpdate.mockResolvedValue(updated);
const result = await repo.update('st-1', 'hh1', { name: 'Updated' });
expect(result).toEqual(updated);
});
it('returns null when not found', async () => {
mockFindOneAndUpdate.mockResolvedValue(null);
expect(await repo.update('missing', 'hh1', {})).toBeNull();
});
});
describe('deactivate', () => {
it('sets isActive=false and returns store', async () => {
const deactivated = { _id: 'st-1', isActive: false };
mockFindOneAndUpdate.mockResolvedValue(deactivated);
const result = await repo.deactivate('st-1', 'hh1');
expect(result).toEqual(deactivated);
});
it('returns null when not found', async () => {
mockFindOneAndUpdate.mockResolvedValue(null);
expect(await repo.deactivate('missing', 'hh1')).toBeNull();
});
});
});