129 lines
3.7 KiB
TypeScript
129 lines
3.7 KiB
TypeScript
|
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||
|
|
|
||
|
|
// Use vi.hoisted so mocks are available in vi.mock factory (which is hoisted)
|
||
|
|
const { mockLean, mockExec, mockFindOne, mockFindById, mockFindOneAndUpdate, mockSave } =
|
||
|
|
vi.hoisted(() => {
|
||
|
|
const mockExec = vi.fn();
|
||
|
|
const mockLean = vi.fn(() => ({ exec: mockExec }));
|
||
|
|
return {
|
||
|
|
mockExec,
|
||
|
|
mockLean,
|
||
|
|
mockFindOne: vi.fn(() => ({ lean: mockLean })),
|
||
|
|
mockFindById: vi.fn(() => ({ lean: mockLean })),
|
||
|
|
mockFindOneAndUpdate: vi.fn(() => ({ exec: mockExec })),
|
||
|
|
mockSave: vi.fn(),
|
||
|
|
};
|
||
|
|
});
|
||
|
|
|
||
|
|
vi.mock('../../schemas/user.schema.js', () => {
|
||
|
|
class MockUserModel {
|
||
|
|
_data: Record<string, unknown>;
|
||
|
|
constructor(data: Record<string, unknown>) {
|
||
|
|
this._data = data;
|
||
|
|
Object.assign(this, data);
|
||
|
|
}
|
||
|
|
save() {
|
||
|
|
mockSave();
|
||
|
|
return Promise.resolve(this);
|
||
|
|
}
|
||
|
|
toObject() {
|
||
|
|
return { _id: 'new-id', ...this._data };
|
||
|
|
}
|
||
|
|
static findOne = mockFindOne;
|
||
|
|
static findById = mockFindById;
|
||
|
|
static findOneAndUpdate = mockFindOneAndUpdate;
|
||
|
|
}
|
||
|
|
return { UserModel: MockUserModel };
|
||
|
|
});
|
||
|
|
|
||
|
|
import { UsersRepository } from './users.repository.js';
|
||
|
|
|
||
|
|
describe('UsersRepository', () => {
|
||
|
|
let repo: UsersRepository;
|
||
|
|
|
||
|
|
beforeEach(() => {
|
||
|
|
vi.clearAllMocks();
|
||
|
|
repo = new UsersRepository();
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('findByKeycloakId', () => {
|
||
|
|
it('calls findOne with keycloakId and returns lean result', async () => {
|
||
|
|
const user = { _id: 'u1', keycloakId: 'kc-1' };
|
||
|
|
mockExec.mockResolvedValue(user);
|
||
|
|
|
||
|
|
const result = await repo.findByKeycloakId('kc-1');
|
||
|
|
|
||
|
|
expect(mockFindOne).toHaveBeenCalledWith({ keycloakId: 'kc-1' }, null, {
|
||
|
|
session: undefined,
|
||
|
|
});
|
||
|
|
expect(mockLean).toHaveBeenCalled();
|
||
|
|
expect(mockExec).toHaveBeenCalled();
|
||
|
|
expect(result).toEqual(user);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('findById', () => {
|
||
|
|
it('calls findById and returns lean result', async () => {
|
||
|
|
const user = { _id: 'u1' };
|
||
|
|
mockExec.mockResolvedValue(user);
|
||
|
|
|
||
|
|
const result = await repo.findById('u1');
|
||
|
|
|
||
|
|
expect(mockFindById).toHaveBeenCalledWith('u1');
|
||
|
|
expect(result).toEqual(user);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('create', () => {
|
||
|
|
it('creates a new user and returns plain object', async () => {
|
||
|
|
mockSave.mockResolvedValue({});
|
||
|
|
|
||
|
|
const data = {
|
||
|
|
keycloakId: 'kc-1',
|
||
|
|
email: 'test@example.com',
|
||
|
|
displayName: 'Test',
|
||
|
|
householdIds: [],
|
||
|
|
};
|
||
|
|
const result = await repo.create(data as never);
|
||
|
|
|
||
|
|
expect(mockSave).toHaveBeenCalled();
|
||
|
|
expect(result).toMatchObject({ keycloakId: 'kc-1' });
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('update', () => {
|
||
|
|
it('calls findOneAndUpdate with $set', async () => {
|
||
|
|
const updated = { _id: 'u1', displayName: 'Updated' };
|
||
|
|
mockExec.mockResolvedValue(updated);
|
||
|
|
|
||
|
|
const result = await repo.update('kc-1', { displayName: 'Updated' } as never);
|
||
|
|
|
||
|
|
expect(mockFindOneAndUpdate).toHaveBeenCalledWith(
|
||
|
|
{ keycloakId: 'kc-1' },
|
||
|
|
{ $set: { displayName: 'Updated' } },
|
||
|
|
{ new: true, lean: true, session: undefined },
|
||
|
|
);
|
||
|
|
expect(result).toEqual(updated);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('upsertFromToken', () => {
|
||
|
|
it('upserts user with $set and $setOnInsert', async () => {
|
||
|
|
const upserted = { _id: 'u1', keycloakId: 'kc-1' };
|
||
|
|
mockExec.mockResolvedValue(upserted);
|
||
|
|
|
||
|
|
const result = await repo.upsertFromToken('kc-1', 'a@b.com', 'Name');
|
||
|
|
|
||
|
|
expect(mockFindOneAndUpdate).toHaveBeenCalledWith(
|
||
|
|
{ keycloakId: 'kc-1' },
|
||
|
|
{
|
||
|
|
$set: { email: 'a@b.com', displayName: 'Name' },
|
||
|
|
$setOnInsert: { keycloakId: 'kc-1', householdIds: [], defaultHouseholdId: null },
|
||
|
|
},
|
||
|
|
{ upsert: true, new: true, lean: true },
|
||
|
|
);
|
||
|
|
expect(result).toEqual(upserted);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
});
|