brackt/app/models/__tests__/participant-expected-value.test.ts
Chris Parsons 8ca1c9cf94
Some checks failed
🚀 Deploy / 🧪 Test (pull_request) Failing after 3m8s
🚀 Deploy / ʦ🔍 Typecheck & Lint (pull_request) Successful in 2m8s
🚀 Deploy / 🐳 Build (pull_request) Has been skipped
🚀 Deploy / 🚀 Deploy (pull_request) Has been skipped
Fix hook/test timeouts from dynamic imports in beforeEach/test bodies
Two patterns causing CI timeouts:

1. admin.sports-seasons.$id.test.ts: vi.resetModules() + multiple
   await import() in beforeEach forced full module re-evaluation on
   every test, exceeding the 10s hook timeout.

2. participant-expected-value.test.ts: await import() of the module
   under test inside test bodies caused the first import to run within
   the 5s test window. Also deleted 13 expect(true).toBe(true) stubs
   and used vi.hoisted() to make mock factories work with static imports.

Both files now use static top-level imports.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 22:22:21 -07:00

88 lines
3.1 KiB
TypeScript

import { describe, it, expect, vi, beforeEach } from "vitest";
import { calculateReplacementLevel, calculateVORP } from "~/services/ev-calculator";
import { syncVorpForSeason } from "../participant-expected-value";
const { mockUpdate, mockSet, mockDb, mockSqlFn } = vi.hoisted(() => {
const update = vi.fn();
const set = vi.fn();
const sqlFn = Object.assign(vi.fn(() => ({})), { join: vi.fn(() => ({})) });
const db = { update, select: vi.fn() };
return { mockUpdate: update, mockSet: set, mockDb: db, mockSqlFn: sqlFn };
});
vi.mock("~/database/context", () => ({
database: () => mockDb,
}));
vi.mock("~/database/schema", () => ({
seasonParticipants: { id: "id" },
seasonParticipantExpectedValues: {
participantId: "participantId",
sportsSeasonId: "sportsSeasonId",
},
}));
vi.mock("drizzle-orm", () => ({
eq: vi.fn((field, value) => ({ field, value })),
and: vi.fn((...args) => ({ and: args })),
count: vi.fn(() => ({ count: true })),
sql: mockSqlFn,
}));
describe("syncVorpForSeason", () => {
beforeEach(() => {
vi.clearAllMocks();
});
it("calculates correct VORP values for 14 participants with EVs 100 down to 35 (step 5)", () => {
// 14 participants: EVs = 100, 95, 90, 85, 80, 75, 70, 65, 60, 55, 50, 45, 40, 35
// replacement level = avg of positions 12-14 (0-indexed 11-13) = avg(45, 40, 35) = 40
const evValues = Array.from({ length: 14 }, (_, i) => 100 - i * 5);
const replacementLevel = calculateReplacementLevel(evValues);
expect(replacementLevel).toBe(40);
expect(calculateVORP(100, replacementLevel)).toBe(60);
expect(calculateVORP(35, replacementLevel)).toBe(-5);
});
it("returns early when no EVs exist for the season", async () => {
const mockSelectChain = {
from: vi.fn().mockReturnThis(),
where: vi.fn().mockResolvedValue([]),
};
mockDb.select = vi.fn().mockReturnValue(mockSelectChain);
await syncVorpForSeason("season-empty");
expect(mockUpdate).not.toHaveBeenCalled();
});
it("calls db.update with correct vorpValue for each participant", async () => {
// 3 participants: EVs 100, 70, 40
// replacement level = avg of positions 12-14, clamped to [40] → 40
// VORP: 100→60, 70→30, 40→0
const mockEvRecords = [
{ participantId: "p1", expectedValue: "100", sportsSeasonId: "season-1" },
{ participantId: "p2", expectedValue: "70", sportsSeasonId: "season-1" },
{ participantId: "p3", expectedValue: "40", sportsSeasonId: "season-1" },
];
const mockSelectChain = {
from: vi.fn().mockReturnThis(),
where: vi.fn().mockResolvedValue(mockEvRecords),
};
mockDb.select = vi.fn().mockReturnValue(mockSelectChain);
const mockWhereResolved = vi.fn().mockResolvedValue([]);
mockSet.mockReturnValue({ where: mockWhereResolved });
mockUpdate.mockReturnValue({ set: mockSet });
await syncVorpForSeason("season-1");
expect(mockUpdate).toHaveBeenCalledTimes(1);
expect(mockSet).toHaveBeenCalledTimes(1);
const setArg = mockSet.mock.calls[0][0];
expect(setArg).toHaveProperty("vorpValue");
expect(setArg).toHaveProperty("updatedAt");
});
});