import assert from 'node:assert/strict'; import test from 'node:test'; import { createPasswordRecoveryService } from '../../src/modules/auth/services/password-recovery-service.js'; test('does not issue a token for an unknown email while recording a generic request', async () => { let resetIssued = false; const auditEvents = []; const service = createPasswordRecoveryService({ passwordResetRepository: { async issue() { resetIssued = true; } }, securityAuditRepository: { async record(event) { auditEvents.push(event); } }, userRepository: { async findAuthenticationUserByEmail() { return null; } }, }); await service.requestReset({ email: 'unknown@example.test' }); assert.equal(resetIssued, false); assert.deepEqual(auditEvents, [ { event: 'PASSWORD_RESET_REQUESTED', ipAddress: null, userAgent: null }, ]); }); test('delivers a reset token without persisting the raw token', async () => { let issuedReset; let deliveredReset; const service = createPasswordRecoveryService({ now: () => new Date('2026-09-07T00:00:00.000Z'), passwordResetNotifier: { async send(reset) { deliveredReset = reset; } }, passwordResetRepository: { async issue(reset) { issuedReset = reset; } }, userRepository: { async findAuthenticationUserByEmail() { return { id: 'user-id', email: 'admin@example.test' }; }, }, }); await service.requestReset({ email: 'admin@example.test' }); assert.equal(issuedReset.userId, 'user-id'); assert.notEqual(issuedReset.tokenHash, deliveredReset.token); assert.equal(deliveredReset.email, 'admin@example.test'); assert.equal(deliveredReset.expiresAt.toISOString(), '2026-09-07T01:00:00.000Z'); }); test('consumes a reset token once and audits a successful password reset', async () => { let consumedReset; const auditEvents = []; const service = createPasswordRecoveryService({ now: () => new Date('2026-09-07T00:00:00.000Z'), passwordHasher: async (password) => `hashed:${password}`, passwordResetRepository: { async consume(reset) { consumedReset = reset; return 'user-id'; }, }, securityAuditRepository: { async record(event) { auditEvents.push(event); } }, }); await service.resetPassword({ token: 'a-valid-reset-token', password: 'new-password-value' }); assert.equal(consumedReset.passwordHash, 'hashed:new-password-value'); assert.notEqual(consumedReset.tokenHash, 'a-valid-reset-token'); assert.deepEqual(auditEvents, [ { userId: 'user-id', event: 'PASSWORD_RESET', ipAddress: null, userAgent: null }, ]); }); test('rejects expired or previously used reset tokens', async () => { const service = createPasswordRecoveryService({ passwordHasher: async () => 'new-password-hash', passwordResetRepository: { async consume() { return null; } }, }); await assert.rejects( () => service.resetPassword({ token: 'invalid-reset-token', password: 'new-password-value' }), (error) => error.code === 'PASSWORD_RESET_TOKEN_INVALID', ); });