import { describe, expect, it, vi } from 'vitest'; import { AuthService } from './AuthService'; import { Result } from '@core/shared/application/Result'; class FakeAuthSessionPresenter { private model: any = null; reset() { this.model = null; } present(model: any) { this.model = model; } get responseModel() { if (!this.model) throw new Error('Presenter not presented'); return this.model; } } class FakeCommandResultPresenter { private model: any = null; reset() { this.model = null; } present(model: any) { this.model = model; } get responseModel() { if (!this.model) throw new Error('Presenter not presented'); return this.model; } } class FakeForgotPasswordPresenter { private model: any = null; reset() { this.model = null; } present(model: any) { this.model = model; } get responseModel() { if (!this.model) throw new Error('Presenter not presented'); return this.model; } } class FakeResetPasswordPresenter { private model: any = null; reset() { this.model = null; } present(model: any) { this.model = model; } get responseModel() { if (!this.model) throw new Error('Presenter not presented'); return this.model; } } class FakeDemoLoginPresenter { private model: any = null; reset() { this.model = null; } present(model: any) { this.model = model; } get responseModel() { if (!this.model) throw new Error('Presenter not presented'); return this.model; } } describe('AuthService - New Methods', () => { describe('forgotPassword', () => { it('should execute forgot password use case and return result', async () => { const forgotPasswordPresenter = new FakeForgotPasswordPresenter(); const forgotPasswordUseCase = { execute: vi.fn(async () => { forgotPasswordPresenter.present({ message: 'Reset link sent', magicLink: 'http://example.com/reset?token=abc123' }); return Result.ok(undefined); }), }; const service = new AuthService( { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() } as any, { getCurrentSession: vi.fn(), createSession: vi.fn() } as any, { execute: vi.fn() } as any, { execute: vi.fn() } as any, { execute: vi.fn() } as any, forgotPasswordUseCase as any, { execute: vi.fn() } as any, { execute: vi.fn() } as any, new FakeAuthSessionPresenter() as any, new FakeCommandResultPresenter() as any, forgotPasswordPresenter as any, new FakeResetPasswordPresenter() as any, new FakeDemoLoginPresenter() as any, ); const result = await service.forgotPassword({ email: 'test@example.com' }); expect(forgotPasswordUseCase.execute).toHaveBeenCalledWith({ email: 'test@example.com' }); expect(result).toEqual({ message: 'Reset link sent', magicLink: 'http://example.com/reset?token=abc123', }); }); it('should throw error on use case failure', async () => { const service = new AuthService( { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() } as any, { getCurrentSession: vi.fn(), createSession: vi.fn() } as any, { execute: vi.fn() } as any, { execute: vi.fn() } as any, { execute: vi.fn() } as any, { execute: vi.fn(async () => Result.err({ code: 'RATE_LIMIT_EXCEEDED', details: { message: 'Too many attempts' } })) } as any, { execute: vi.fn() } as any, { execute: vi.fn() } as any, new FakeAuthSessionPresenter() as any, new FakeCommandResultPresenter() as any, new FakeForgotPasswordPresenter() as any, new FakeResetPasswordPresenter() as any, new FakeDemoLoginPresenter() as any, ); await expect(service.forgotPassword({ email: 'test@example.com' })).rejects.toThrow('Too many attempts'); }); }); describe('resetPassword', () => { it('should execute reset password use case and return result', async () => { const resetPasswordPresenter = new FakeResetPasswordPresenter(); const resetPasswordUseCase = { execute: vi.fn(async () => { resetPasswordPresenter.present({ message: 'Password reset successfully' }); return Result.ok(undefined); }), }; const service = new AuthService( { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() } as any, { getCurrentSession: vi.fn(), createSession: vi.fn() } as any, { execute: vi.fn() } as any, { execute: vi.fn() } as any, { execute: vi.fn() } as any, { execute: vi.fn() } as any, resetPasswordUseCase as any, { execute: vi.fn() } as any, new FakeAuthSessionPresenter() as any, new FakeCommandResultPresenter() as any, new FakeForgotPasswordPresenter() as any, resetPasswordPresenter as any, new FakeDemoLoginPresenter() as any, ); const result = await service.resetPassword({ token: 'abc123', newPassword: 'NewPass123!', }); expect(resetPasswordUseCase.execute).toHaveBeenCalledWith({ token: 'abc123', newPassword: 'NewPass123!', }); expect(result).toEqual({ message: 'Password reset successfully' }); }); it('should throw error on use case failure', async () => { const service = new AuthService( { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() } as any, { getCurrentSession: vi.fn(), createSession: vi.fn() } as any, { execute: vi.fn() } as any, { execute: vi.fn() } as any, { execute: vi.fn() } as any, { execute: vi.fn() } as any, { execute: vi.fn(async () => Result.err({ code: 'INVALID_TOKEN', details: { message: 'Invalid token' } })) } as any, { execute: vi.fn() } as any, new FakeAuthSessionPresenter() as any, new FakeCommandResultPresenter() as any, new FakeForgotPasswordPresenter() as any, new FakeResetPasswordPresenter() as any, new FakeDemoLoginPresenter() as any, ); await expect( service.resetPassword({ token: 'invalid', newPassword: 'NewPass123!' }) ).rejects.toThrow('Invalid token'); }); }); describe('demoLogin', () => { it('should execute demo login use case and create session', async () => { const demoLoginPresenter = new FakeDemoLoginPresenter(); const mockUser = { getId: () => ({ value: 'demo-user-123' }), getDisplayName: () => 'Alex Johnson', getEmail: () => 'demo.driver@example.com', getPrimaryDriverId: () => undefined, }; const demoLoginUseCase = { execute: vi.fn(async () => { demoLoginPresenter.present({ user: mockUser }); return Result.ok(undefined); }), }; const identitySessionPort = { getCurrentSession: vi.fn(), createSession: vi.fn(async () => ({ token: 'demo-token-123' })), }; const service = new AuthService( { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() } as any, identitySessionPort as any, { execute: vi.fn() } as any, { execute: vi.fn() } as any, { execute: vi.fn() } as any, { execute: vi.fn() } as any, { execute: vi.fn() } as any, demoLoginUseCase as any, new FakeAuthSessionPresenter() as any, new FakeCommandResultPresenter() as any, new FakeForgotPasswordPresenter() as any, new FakeResetPasswordPresenter() as any, demoLoginPresenter as any, ); const result = await service.demoLogin({ role: 'driver' }); expect(demoLoginUseCase.execute).toHaveBeenCalledWith({ role: 'driver' }); expect(identitySessionPort.createSession).toHaveBeenCalledWith( { id: 'demo-user-123', displayName: 'Alex Johnson', email: 'demo.driver@example.com', }, undefined ); expect(result).toEqual({ token: 'demo-token-123', user: { userId: 'demo-user-123', email: 'demo.driver@example.com', displayName: 'Alex Johnson', role: 'driver', }, }); }); it('should throw error on use case failure', async () => { const service = new AuthService( { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() } as any, { getCurrentSession: vi.fn(), createSession: vi.fn() } as any, { execute: vi.fn() } as any, { execute: vi.fn() } as any, { execute: vi.fn() } as any, { execute: vi.fn() } as any, { execute: vi.fn() } as any, { execute: vi.fn(async () => Result.err({ code: 'DEMO_NOT_ALLOWED', details: { message: 'Demo not allowed' } })) } as any, new FakeAuthSessionPresenter() as any, new FakeCommandResultPresenter() as any, new FakeForgotPasswordPresenter() as any, new FakeResetPasswordPresenter() as any, new FakeDemoLoginPresenter() as any, ); await expect(service.demoLogin({ role: 'driver' })).rejects.toThrow('Demo not allowed'); }); }); });