From 7fd368def3b44e2d30d96dfb5daf3b21023d2d33 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 19 Aug 2026 10:26:17 -0700 Subject: [PATCH] update tests --- .../integration/monitorRepository.test.ts | 72 +++++++++++++++++++ .../services/maintenanceWindowService.test.ts | 4 +- .../unit/services/statusPageService.test.ts | 20 ++++-- 3 files changed, 87 insertions(+), 9 deletions(-) diff --git a/server/test/integration/monitorRepository.test.ts b/server/test/integration/monitorRepository.test.ts index 7144f7f3e..ed7a7a7a6 100644 --- a/server/test/integration/monitorRepository.test.ts +++ b/server/test/integration/monitorRepository.test.ts @@ -31,6 +31,23 @@ const seedMonitor = (teamId: mongoose.Types.ObjectId, name: string, tags: mongoo tags, }); +const makeSnapshot = (id: string, dayOfMonth: number) => ({ + id, + status: true, + responseTime: 100, + createdAt: new Date(2026, 7, dayOfMonth), +}); + +const seedMonitorWithChecks = (teamId: mongoose.Types.ObjectId, name: string, type: string, snapshotIds: string[]) => + MonitorModel.create({ + userId: new mongoose.Types.ObjectId(), + teamId, + name, + type, + url: "https://example.com", + recentChecks: snapshotIds.map((id, i) => makeSnapshot(id, i + 1)), + }); + describe("MongoMonitorsRepository", () => { describe("tag filtering", () => { it("matches ObjectId tag references when filters arrive as query strings", async () => { @@ -51,4 +68,59 @@ describe("MongoMonitorsRepository", () => { expect(summary.totalMonitors).toBe(1); }); }); + + describe("findByIds recentChecks modes", () => { + const seedFixtures = async () => { + const teamId = new mongoose.Types.ObjectId(); + const hardware = await seedMonitorWithChecks(teamId, "hw", "hardware", ["hw-1", "hw-2", "hw-3"]); + const http = await seedMonitorWithChecks(teamId, "web", "http", ["web-1", "web-2"]); + return { ids: [hardware._id.toString(), http._id.toString()] }; + }; + + const checksByName = (monitors: Awaited>) => + Object.fromEntries(monitors.map((monitor) => [monitor.name, monitor.recentChecks.map((check) => check.id)])); + + it("returns full recentChecks by default and for mode 'all'", async () => { + const repo = new MongoMonitorsRepository(); + const { ids } = await seedFixtures(); + + const byDefault = await repo.findByIds(ids); + const byAll = await repo.findByIds(ids, { recentChecks: "all" }); + + for (const monitors of [byDefault, byAll]) { + expect(checksByName(monitors)).toEqual({ hw: ["hw-1", "hw-2", "hw-3"], web: ["web-1", "web-2"] }); + } + }); + + it("strips recentChecks for mode 'none'", async () => { + const repo = new MongoMonitorsRepository(); + const { ids } = await seedFixtures(); + + const monitors = await repo.findByIds(ids, { recentChecks: "none" }); + + expect(checksByName(monitors)).toEqual({ hw: [], web: [] }); + }); + + it("keeps only the newest snapshot for hardware monitors in 'latestHardware' mode", async () => { + const repo = new MongoMonitorsRepository(); + const { ids } = await seedFixtures(); + + const monitors = await repo.findByIds(ids, { recentChecks: "latestHardware" }); + + expect(checksByName(monitors)).toEqual({ hw: ["hw-3"], web: [] }); + }); + + it("returns an empty array in 'latestHardware' mode for a hardware monitor with no recentChecks field at all", async () => { + const repo = new MongoMonitorsRepository(); + const teamId = new mongoose.Types.ObjectId(); + const hardware = await seedMonitorWithChecks(teamId, "hw-fresh", "hardware", []); + // $slice on a missing operand is a hard aggregation error; the $ifNull guard must cover it + await MonitorModel.updateOne({ _id: hardware._id }, { $unset: { recentChecks: 1 } }); + + const monitors = await repo.findByIds([hardware._id.toString()], { recentChecks: "latestHardware" }); + + expect(monitors).toHaveLength(1); + expect(monitors[0].recentChecks).toEqual([]); + }); + }); }); diff --git a/server/test/unit/services/maintenanceWindowService.test.ts b/server/test/unit/services/maintenanceWindowService.test.ts index 481dc5983..691291ebe 100644 --- a/server/test/unit/services/maintenanceWindowService.test.ts +++ b/server/test/unit/services/maintenanceWindowService.test.ts @@ -123,7 +123,7 @@ describe("MaintenanceWindowService", () => { await service.createMaintenanceWindow(defaultCreateParams); - expect(monitorsRepository.findByIds).toHaveBeenCalledWith(["mon-1", "mon-2"], { includeRecentChecks: false }); + expect(monitorsRepository.findByIds).toHaveBeenCalledWith(["mon-1", "mon-2"], { recentChecks: "none" }); }); it("throws 403 when a monitor belongs to a different team", async () => { @@ -404,7 +404,7 @@ describe("MaintenanceWindowService", () => { body: { monitors: ["mon-1", "mon-2"] }, }); - expect(monitorsRepository.findByIds).toHaveBeenCalledWith(["mon-1", "mon-2"], { includeRecentChecks: false }); + expect(monitorsRepository.findByIds).toHaveBeenCalledWith(["mon-1", "mon-2"], { recentChecks: "none" }); }); it("throws 403 when a new monitor belongs to a different team", async () => { diff --git a/server/test/unit/services/statusPageService.test.ts b/server/test/unit/services/statusPageService.test.ts index 4a6fb8c1c..ba3ac298e 100644 --- a/server/test/unit/services/statusPageService.test.ts +++ b/server/test/unit/services/statusPageService.test.ts @@ -376,23 +376,29 @@ describe("StatusPageService", () => { expect(payload.monitors[0]).not.toHaveProperty("dailyChecks"); } expect(checksRepo.getDailyStatusBuckets).not.toHaveBeenCalled(); - expect(monitorsRepo.findByIds).toHaveBeenCalledWith(["mon-1"], { includeRecentChecks: true }); + expect(monitorsRepo.findByIds).toHaveBeenCalledWith(["mon-1"], { recentChecks: "all" }); }); - it("attaches dailyChecks, empties recentChecks, and echoes range metadata for a day range", async () => { + it("attaches dailyChecks, passes the repo-trimmed recentChecks through, and echoes range metadata for a day range", async () => { const { service, checksRepo, monitorsRepo } = createService(); const bucket = { monitorId: "mon-1", date: "2026-08-01", totalChecks: 10, upChecks: 9, downChecks: 1, avgResponseTime: 120 }; + const hardwareSnapshot = { id: "chk-1" } as CheckSnapshot; (checksRepo.getDailyStatusBuckets as jest.Mock).mockResolvedValue([bucket]); - (monitorsRepo.findByIds as jest.Mock).mockResolvedValue([makeMonitor({ recentChecks: [{ id: "chk-1" } as CheckSnapshot] })]); - const page = makeStatusPage({ isPublished: true, timezone: "America/Toronto" }); + (monitorsRepo.findByIds as jest.Mock).mockResolvedValue([ + makeMonitor({ id: "mon-1", type: "hardware", recentChecks: [hardwareSnapshot] }), + makeMonitor({ id: "mon-2", recentChecks: [] }), + ]); + const page = makeStatusPage({ isPublished: true, timezone: "America/Toronto", monitors: ["mon-1", "mon-2"] }); const payload = await service.getPublicStatusPagePayload(page, undefined, "30d"); - expect(checksRepo.getDailyStatusBuckets).toHaveBeenCalledWith(["mon-1"], 30, "America/Toronto"); - expect(monitorsRepo.findByIds).toHaveBeenCalledWith(["mon-1"], { includeRecentChecks: false }); + expect(checksRepo.getDailyStatusBuckets).toHaveBeenCalledWith(["mon-1", "mon-2"], 30, "America/Toronto"); + expect(monitorsRepo.findByIds).toHaveBeenCalledWith(["mon-1", "mon-2"], { recentChecks: "latestHardware" }); expect(payload).toMatchObject({ range: "30d", bucketTimezone: "America/Toronto", checkTTLDays: 30 }); - expect(payload.monitors[0].recentChecks).toEqual([]); + expect(payload.monitors[0].recentChecks).toEqual([hardwareSnapshot]); expect(payload.monitors[0].dailyChecks).toEqual([bucket]); + expect(payload.monitors[1].recentChecks).toEqual([]); + expect(payload.monitors[1].dailyChecks).toEqual([]); for (const field of SENSITIVE_FIELDS) { expect(payload.monitors[0]).not.toHaveProperty(field); }