// ABOUTME: Unit tests for Garmin status API route. // ABOUTME: Tests GET /api/garmin/status for connection status and token expiry. import type { NextRequest } from "next/server"; import { NextResponse } from "next/server"; import { beforeEach, describe, expect, it, vi } from "vitest"; import type { User } from "@/types"; // Module-level variable to control mock user in tests let currentMockUser: User | null = null; // Create a mock PocketBase client that returns the current mock user const createMockPb = () => ({ collection: vi.fn(() => ({ getOne: vi.fn(() => Promise.resolve( currentMockUser ? { ...currentMockUser, garminTokenExpiresAt: currentMockUser.garminTokenExpiresAt?.toISOString(), } : null, ), ), })), }); // Mock PocketBase vi.mock("@/lib/pocketbase", () => ({ createPocketBaseClient: vi.fn(() => createMockPb()), })); // Mock the auth-middleware module vi.mock("@/lib/auth-middleware", () => ({ withAuth: vi.fn((handler) => { return async (request: NextRequest) => { if (!currentMockUser) { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } const mockPb = createMockPb(); return handler(request, currentMockUser, mockPb); }; }), })); import { GET } from "./route"; describe("GET /api/garmin/status", () => { beforeEach(() => { vi.clearAllMocks(); currentMockUser = null; }); it("returns 401 when not authenticated", async () => { currentMockUser = null; const mockRequest = {} as NextRequest; const response = await GET(mockRequest); expect(response.status).toBe(401); const body = await response.json(); expect(body.error).toBe("Unauthorized"); }); it("returns connected false when user has no tokens", async () => { currentMockUser = { id: "user123", email: "test@example.com", garminConnected: false, garminOauth1Token: "", garminOauth2Token: "", garminTokenExpiresAt: new Date("2025-01-01"), garminRefreshTokenExpiresAt: null, calendarToken: "cal-secret-token", lastPeriodDate: new Date("2025-01-15"), cycleLength: 28, notificationTime: "07:30", timezone: "America/New_York", activeOverrides: [], created: new Date("2024-01-01"), updated: new Date("2025-01-10"), }; const mockRequest = {} as NextRequest; const response = await GET(mockRequest); expect(response.status).toBe(200); const body = await response.json(); expect(body.connected).toBe(false); }); it("returns connected true when user has valid tokens", async () => { const futureDate = new Date(); futureDate.setDate(futureDate.getDate() + 30); currentMockUser = { id: "user123", email: "test@example.com", garminConnected: true, garminOauth1Token: "encrypted-token", garminOauth2Token: "encrypted-token", garminTokenExpiresAt: futureDate, garminRefreshTokenExpiresAt: null, calendarToken: "cal-secret-token", lastPeriodDate: new Date("2025-01-15"), cycleLength: 28, notificationTime: "07:30", timezone: "America/New_York", activeOverrides: [], created: new Date("2024-01-01"), updated: new Date("2025-01-10"), }; const mockRequest = {} as NextRequest; const response = await GET(mockRequest); expect(response.status).toBe(200); const body = await response.json(); expect(body.connected).toBe(true); }); it("returns daysUntilExpiry when connected", async () => { const futureDate = new Date(); futureDate.setDate(futureDate.getDate() + 30); currentMockUser = { id: "user123", email: "test@example.com", garminConnected: true, garminOauth1Token: "encrypted-token", garminOauth2Token: "encrypted-token", garminTokenExpiresAt: futureDate, garminRefreshTokenExpiresAt: null, calendarToken: "cal-secret-token", lastPeriodDate: new Date("2025-01-15"), cycleLength: 28, notificationTime: "07:30", timezone: "America/New_York", activeOverrides: [], created: new Date("2024-01-01"), updated: new Date("2025-01-10"), }; const mockRequest = {} as NextRequest; const response = await GET(mockRequest); expect(response.status).toBe(200); const body = await response.json(); expect(body.daysUntilExpiry).toBeGreaterThanOrEqual(29); expect(body.daysUntilExpiry).toBeLessThanOrEqual(30); }); it("returns null daysUntilExpiry when not connected", async () => { currentMockUser = { id: "user123", email: "test@example.com", garminConnected: false, garminOauth1Token: "", garminOauth2Token: "", garminTokenExpiresAt: new Date("2025-01-01"), garminRefreshTokenExpiresAt: null, calendarToken: "cal-secret-token", lastPeriodDate: new Date("2025-01-15"), cycleLength: 28, notificationTime: "07:30", timezone: "America/New_York", activeOverrides: [], created: new Date("2024-01-01"), updated: new Date("2025-01-10"), }; const mockRequest = {} as NextRequest; const response = await GET(mockRequest); expect(response.status).toBe(200); const body = await response.json(); expect(body.daysUntilExpiry).toBeNull(); }); it("returns expired true when tokens have expired", async () => { const pastDate = new Date(); pastDate.setDate(pastDate.getDate() - 5); currentMockUser = { id: "user123", email: "test@example.com", garminConnected: true, garminOauth1Token: "encrypted-token", garminOauth2Token: "encrypted-token", garminTokenExpiresAt: pastDate, garminRefreshTokenExpiresAt: null, calendarToken: "cal-secret-token", lastPeriodDate: new Date("2025-01-15"), cycleLength: 28, notificationTime: "07:30", timezone: "America/New_York", activeOverrides: [], created: new Date("2024-01-01"), updated: new Date("2025-01-10"), }; const mockRequest = {} as NextRequest; const response = await GET(mockRequest); expect(response.status).toBe(200); const body = await response.json(); expect(body.connected).toBe(true); expect(body.expired).toBe(true); expect(body.daysUntilExpiry).toBeLessThan(0); }); it("returns expired false when tokens are valid", async () => { const futureDate = new Date(); futureDate.setDate(futureDate.getDate() + 30); currentMockUser = { id: "user123", email: "test@example.com", garminConnected: true, garminOauth1Token: "encrypted-token", garminOauth2Token: "encrypted-token", garminTokenExpiresAt: futureDate, garminRefreshTokenExpiresAt: null, calendarToken: "cal-secret-token", lastPeriodDate: new Date("2025-01-15"), cycleLength: 28, notificationTime: "07:30", timezone: "America/New_York", activeOverrides: [], created: new Date("2024-01-01"), updated: new Date("2025-01-10"), }; const mockRequest = {} as NextRequest; const response = await GET(mockRequest); expect(response.status).toBe(200); const body = await response.json(); expect(body.expired).toBe(false); }); it("returns warningLevel 'critical' when expiring in 7 days or less", async () => { const futureDate = new Date(); futureDate.setDate(futureDate.getDate() + 5); currentMockUser = { id: "user123", email: "test@example.com", garminConnected: true, garminOauth1Token: "encrypted-token", garminOauth2Token: "encrypted-token", garminTokenExpiresAt: futureDate, garminRefreshTokenExpiresAt: null, calendarToken: "cal-secret-token", lastPeriodDate: new Date("2025-01-15"), cycleLength: 28, notificationTime: "07:30", timezone: "America/New_York", activeOverrides: [], created: new Date("2024-01-01"), updated: new Date("2025-01-10"), }; const mockRequest = {} as NextRequest; const response = await GET(mockRequest); expect(response.status).toBe(200); const body = await response.json(); expect(body.warningLevel).toBe("critical"); }); it("returns warningLevel 'warning' when expiring in 8-14 days", async () => { const futureDate = new Date(); futureDate.setDate(futureDate.getDate() + 10); currentMockUser = { id: "user123", email: "test@example.com", garminConnected: true, garminOauth1Token: "encrypted-token", garminOauth2Token: "encrypted-token", garminTokenExpiresAt: futureDate, garminRefreshTokenExpiresAt: null, calendarToken: "cal-secret-token", lastPeriodDate: new Date("2025-01-15"), cycleLength: 28, notificationTime: "07:30", timezone: "America/New_York", activeOverrides: [], created: new Date("2024-01-01"), updated: new Date("2025-01-10"), }; const mockRequest = {} as NextRequest; const response = await GET(mockRequest); expect(response.status).toBe(200); const body = await response.json(); expect(body.warningLevel).toBe("warning"); }); it("returns warningLevel null when more than 14 days until expiry", async () => { const futureDate = new Date(); futureDate.setDate(futureDate.getDate() + 30); currentMockUser = { id: "user123", email: "test@example.com", garminConnected: true, garminOauth1Token: "encrypted-token", garminOauth2Token: "encrypted-token", garminTokenExpiresAt: futureDate, garminRefreshTokenExpiresAt: null, calendarToken: "cal-secret-token", lastPeriodDate: new Date("2025-01-15"), cycleLength: 28, notificationTime: "07:30", timezone: "America/New_York", activeOverrides: [], created: new Date("2024-01-01"), updated: new Date("2025-01-10"), }; const mockRequest = {} as NextRequest; const response = await GET(mockRequest); expect(response.status).toBe(200); const body = await response.json(); expect(body.warningLevel).toBeNull(); }); it("returns warningLevel null when not connected", async () => { currentMockUser = { id: "user123", email: "test@example.com", garminConnected: false, garminOauth1Token: "", garminOauth2Token: "", garminTokenExpiresAt: new Date("2025-01-01"), garminRefreshTokenExpiresAt: null, calendarToken: "cal-secret-token", lastPeriodDate: new Date("2025-01-15"), cycleLength: 28, notificationTime: "07:30", timezone: "America/New_York", activeOverrides: [], created: new Date("2024-01-01"), updated: new Date("2025-01-10"), }; const mockRequest = {} as NextRequest; const response = await GET(mockRequest); expect(response.status).toBe(200); const body = await response.json(); expect(body.warningLevel).toBeNull(); }); });