Files
gridpilot.gg/adapters/identity/persistence/inmemory/InMemoryMagicLinkRepository.test.ts
Marc Mintel cfc30c79a8
Some checks failed
CI / lint-typecheck (pull_request) Failing after 12s
CI / tests (pull_request) Has been skipped
CI / contract-tests (pull_request) Has been skipped
CI / e2e-tests (pull_request) Has been skipped
CI / comment-pr (pull_request) Has been skipped
CI / commit-types (pull_request) Has been skipped
code quality
2026-01-26 12:52:24 +01:00

141 lines
4.3 KiB
TypeScript

import { beforeEach, describe, expect, it } from 'vitest';
import { InMemoryMagicLinkRepository } from './InMemoryMagicLinkRepository';
import type { Logger } from '@core/shared/domain/Logger';
const mockLogger: Logger = {
debug: () => {},
info: () => {},
warn: () => {},
error: () => {},
};
describe('InMemoryMagicLinkRepository', () => {
let repository: InMemoryMagicLinkRepository;
beforeEach(() => {
repository = new InMemoryMagicLinkRepository(mockLogger);
});
describe('createPasswordResetRequest', () => {
it('should create a password reset request', async () => {
const request = {
email: 'test@example.com',
token: 'abc123',
expiresAt: new Date(Date.now() + 15 * 60 * 1000),
userId: 'user-123',
};
await repository.createPasswordResetRequest(request);
const found = await repository.findByToken('abc123');
expect(found).toEqual(request);
});
it('should enforce rate limiting', async () => {
const request = {
email: 'test@example.com',
token: 'token1',
expiresAt: new Date(Date.now() + 15 * 60 * 1000),
userId: 'user-123',
};
// Create 3 requests for same email
await repository.createPasswordResetRequest({ ...request, token: 'token1' });
await repository.createPasswordResetRequest({ ...request, token: 'token2' });
await repository.createPasswordResetRequest({ ...request, token: 'token3' });
// 4th should fail
const result = await repository.checkRateLimit('test@example.com');
expect(result.isErr()).toBe(true);
});
it('should allow requests after time window expires', async () => {
const now = Date.now();
const request = {
email: 'test@example.com',
token: 'token1',
expiresAt: new Date(now + 15 * 60 * 1000),
userId: 'user-123',
};
// Mock Date.now to return time after rate limit window
const originalNow = Date.now;
Date.now = () => now + (16 * 60 * 1000); // 16 minutes later
try {
await repository.createPasswordResetRequest(request);
const found = await repository.findByToken('token1');
expect(found).toBeDefined();
} finally {
Date.now = originalNow;
}
});
});
describe('findByToken', () => {
it('should find existing token', async () => {
const request = {
email: 'test@example.com',
token: 'abc123',
expiresAt: new Date(Date.now() + 15 * 60 * 1000),
userId: 'user-123',
};
await repository.createPasswordResetRequest(request);
const found = await repository.findByToken('abc123');
expect(found).toEqual(request);
});
it('should return null for non-existent token', async () => {
const found = await repository.findByToken('nonexistent');
expect(found).toBeNull();
});
});
describe('markAsUsed', () => {
it('should mark token as used', async () => {
const request = {
email: 'test@example.com',
token: 'abc123',
expiresAt: new Date(Date.now() + 15 * 60 * 1000),
userId: 'user-123',
};
await repository.createPasswordResetRequest(request);
await repository.markAsUsed('abc123');
const found = await repository.findByToken('abc123');
expect(found).toBeNull();
});
it('should handle non-existent token gracefully', async () => {
await expect(repository.markAsUsed('nonexistent')).resolves.not.toThrow();
});
});
describe('checkRateLimit', () => {
it('should allow requests under limit', async () => {
const result = await repository.checkRateLimit('test@example.com');
expect(result.isOk()).toBe(true);
});
it('should reject requests over limit', async () => {
const email = 'test@example.com';
const request = {
email,
token: 'token',
expiresAt: new Date(Date.now() + 15 * 60 * 1000),
userId: 'user-123',
};
// Create 3 requests
await repository.createPasswordResetRequest({ ...request, token: 'token1' });
await repository.createPasswordResetRequest({ ...request, token: 'token2' });
await repository.createPasswordResetRequest({ ...request, token: 'token3' });
const result = await repository.checkRateLimit(email);
expect(result.isErr()).toBe(true);
});
});
});