253 lines
9.0 KiB
TypeScript
253 lines
9.0 KiB
TypeScript
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');
|
|
});
|
|
});
|
|
}); |