1
0
Fork 0

test(int): cover imminent reminder query boundaries

Window edges, post-start grace zone, and exclusions for marked
missions, missing roll-call, non-unit visibility, and draft status.
This commit is contained in:
Jason Fraley 2026-09-18 13:09:35 -04:00
parent 35769ea0f6
commit 8f7573f742

View file

@ -0,0 +1,214 @@
import { getPayload, Payload } from "payload";
import config from "@/payload.config";
import { afterAll, beforeAll, describe, expect, it } from "vitest";
import type { Campaign, Map as MissionMap, Mission, User } from "@/payload-types";
import {
IMMINENT_REMINDER_GRACE_MS,
IMMINENT_REMINDER_WINDOW_MS,
getImminentReminderMissions,
} from "@/lib/intelligence/imminentReminders";
let payload: Payload;
const RUN = `imr-${Date.now().toString(36)}`;
describe("Imminent-op reminder query", () => {
let mapId: number;
let campaignId: number;
let authorId: number;
const missionIds: number[] = [];
beforeAll(async () => {
const payloadConfig = await config;
payload = await getPayload({ config: payloadConfig });
const map = (await payload.create({
collection: "maps",
data: { name: `${RUN} Map`, worldSizeWidth: 8192, worldSizeHeight: 8192, basemapMode: "image" },
overrideAccess: true,
depth: 0,
})) as unknown as MissionMap;
mapId = map.id;
const campaign = (await payload.create({
collection: "campaigns",
data: { name: `${RUN} Campaign`, summary: "Imminent reminder test campaign", status: "concept", campaignMode: "custom" },
overrideAccess: true,
depth: 0,
})) as unknown as Campaign;
campaignId = campaign.id;
const author = (await payload.create({
collection: "users",
data: {
username: `${RUN}-author`,
discordUsername: `${RUN}-author`,
displayName: "AUTHOR",
steamId: `7656119${Math.floor(Math.random() * 1e9)}`,
password: "Test123",
roles: ["user"],
},
overrideAccess: true,
depth: 0,
})) as unknown as User;
authorId = author.id;
});
afterAll(async () => {
for (const id of missionIds) {
await payload.delete({ collection: "missions", id, overrideAccess: true }).catch(() => {});
}
await payload
.delete({ collection: "campaigns", id: campaignId, overrideAccess: true })
.catch(() => {});
await payload.delete({ collection: "maps", id: mapId, overrideAccess: true }).catch(() => {});
// User deletion trips FK constraints unless the hook-provisioned
// personal bank account and profile are removed first.
const accounts = await payload
.find({
collection: "bank-accounts",
where: { ownerUser: { equals: authorId } },
limit: 5,
depth: 0,
overrideAccess: true,
})
.catch(() => null);
for (const account of accounts?.docs ?? []) {
await payload
.delete({ collection: "bank-accounts", id: account.id, overrideAccess: true })
.catch(() => {});
}
const profiles = await payload
.find({
collection: "profiles",
where: { user: { equals: authorId } },
limit: 5,
depth: 0,
overrideAccess: true,
})
.catch(() => null);
for (const profile of profiles?.docs ?? []) {
await payload
.delete({ collection: "profiles", id: profile.id, overrideAccess: true })
.catch(() => {});
}
await payload
.delete({ collection: "users", id: authorId, overrideAccess: true })
.catch(() => {});
});
const makeMission = async (
label: string,
overrides: {
status?: Mission["ownershipAndStatus"]["status"];
visibility?: Mission["ownershipAndStatus"]["visibility"];
start: Date;
withRollCall?: boolean;
marked?: boolean;
},
): Promise<Mission> => {
const mission = (await payload.create({
collection: "missions",
data: {
name: `${RUN} ${label}`,
codeName: `${RUN}-${label}`,
summary: "Imminent reminder boundary test mission",
operationType: "main",
classification: {
map: mapId,
missionType: "PvE",
campaign: campaignId,
startDateTime: overrides.start.toISOString(),
estimatedDuration: 60,
},
ownershipAndStatus: {
authors: [authorId],
status: overrides.status ?? "Scheduled",
visibility: overrides.visibility ?? "unit",
},
missionRoles: {
maxPlayers: 16,
},
gameDetails: {
serverDetails: {
serverIp: "127.0.0.1",
serverPort: 2302,
},
},
briefing: [],
...(overrides.withRollCall === false
? {}
: { discordMessageId: `${RUN}-${label}-message` }),
...(overrides.marked ? { imminentReminderSentAt: new Date().toISOString() } : {}),
},
overrideAccess: true,
depth: 0,
})) as unknown as Mission;
missionIds.push(mission.id);
return mission;
};
it("finds posted Ready/Scheduled ops starting inside the 15 minute window", async () => {
const now = new Date();
const start = new Date(now.getTime() + IMMINENT_REMINDER_WINDOW_MS - 60_000);
const ready = await makeMission("in-window-ready", { status: "Ready", start });
const scheduled = await makeMission("in-window-scheduled", { status: "Scheduled", start });
const found = await getImminentReminderMissions(payload, now);
expect(found.map((m) => m.id)).toContain(ready.id);
expect(found.map((m) => m.id)).toContain(scheduled.id);
});
it("includes the exact window edge and the grace zone just past the start", async () => {
const now = new Date();
const edge = await makeMission("window-edge", {
start: new Date(now.getTime() + IMMINENT_REMINDER_WINDOW_MS),
});
const justStarted = await makeMission("grace-zone", {
start: new Date(now.getTime() - 5 * 60_000),
});
const found = await getImminentReminderMissions(payload, now);
expect(found.map((m) => m.id)).toContain(edge.id);
expect(found.map((m) => m.id)).toContain(justStarted.id);
});
it("excludes ops outside the window, past the grace bound, marked, without a roll-call, or not unit-visible", async () => {
const now = new Date();
const tooEarly = await makeMission("too-early", {
start: new Date(now.getTime() + IMMINENT_REMINDER_WINDOW_MS + 60_000),
});
const tooLate = await makeMission("too-late", {
start: new Date(now.getTime() - IMMINENT_REMINDER_GRACE_MS - 60_000),
});
const alreadyReminded = await makeMission("already-reminded", {
start: new Date(now.getTime() + 10 * 60_000),
marked: true,
});
const noRollCall = await makeMission("no-roll-call", {
start: new Date(now.getTime() + 10 * 60_000),
withRollCall: false,
});
const notUnitVisible = await makeMission("not-unit-visible", {
start: new Date(now.getTime() + 10 * 60_000),
visibility: "leadership",
});
const draftStatus = await makeMission("draft-status", {
status: "Planning",
start: new Date(now.getTime() + 10 * 60_000),
});
const foundIds = (await getImminentReminderMissions(payload, now)).map((m) => m.id);
for (const excluded of [
tooEarly,
tooLate,
alreadyReminded,
noRollCall,
notUnitVisible,
draftStatus,
]) {
expect(foundIds).not.toContain(excluded.id);
}
});
});