import { describe, it, expect, vi, beforeEach } from 'vitest' import '../../../test/__mocks__/prisma' import { checkRateLimit, recordAttempt } from '@/lib/rate-limit' import { prisma } from '@/lib/prisma' beforeEach(() => { vi.clearAllMocks() }) describe('checkRateLimit', () => { it('returns not limited when attempts < 10', async () => { vi.mocked(prisma.loginAttempt.count).mockResolvedValue(5) const result = await checkRateLimit('1.2.3.4') expect(result.limited).toBe(false) expect(result.remaining).toBe(5) }) it('returns limited when attempts >= 10', async () => { vi.mocked(prisma.loginAttempt.count).mockResolvedValue(10) const result = await checkRateLimit('1.2.3.4') expect(result.limited).toBe(true) expect(result.remaining).toBe(0) }) it('returns limited when attempts > 10', async () => { vi.mocked(prisma.loginAttempt.count).mockResolvedValue(15) const result = await checkRateLimit('1.2.3.4') expect(result.limited).toBe(true) }) it('returns remaining = 1 when attempts = 9', async () => { vi.mocked(prisma.loginAttempt.count).mockResolvedValue(9) const result = await checkRateLimit('1.2.3.4') expect(result.limited).toBe(false) expect(result.remaining).toBe(1) }) it('queries with a windowStart within the last 15 minutes', async () => { vi.mocked(prisma.loginAttempt.count).mockResolvedValue(0) const before = new Date(Date.now() - 15 * 60 * 1000 - 100) await checkRateLimit('1.2.3.4') const callArg = vi.mocked(prisma.loginAttempt.count).mock.calls[0][0] const windowStart = callArg?.where?.createdAt?.gte as Date expect(windowStart.getTime()).toBeGreaterThan(before.getTime()) }) }) describe('recordAttempt', () => { it('creates a login attempt record', async () => { vi.mocked(prisma.loginAttempt.create).mockResolvedValue({ id: '1', key: '1.2.3.4', createdAt: new Date() }) vi.mocked(prisma.loginAttempt.deleteMany).mockResolvedValue({ count: 0 }) await recordAttempt('1.2.3.4') expect(prisma.loginAttempt.create).toHaveBeenCalledWith({ data: { key: '1.2.3.4' } }) }) it('cleans up old records after creating', async () => { vi.mocked(prisma.loginAttempt.create).mockResolvedValue({ id: '1', key: '1.2.3.4', createdAt: new Date() }) vi.mocked(prisma.loginAttempt.deleteMany).mockResolvedValue({ count: 0 }) await recordAttempt('1.2.3.4') expect(prisma.loginAttempt.deleteMany).toHaveBeenCalledWith( expect.objectContaining({ where: expect.objectContaining({ createdAt: expect.anything() }) }) ) }) })