brackt/app/models/__tests__/regular-season-standings.test.ts

334 lines
10 KiB
TypeScript
Raw Normal View History

import { describe, it, expect, vi, beforeEach } from "vitest";
vi.mock("~/database/context", () => ({
database: vi.fn(),
}));
import {
upsertRegularSeasonStandings,
upsertManualStanding,
getRegularSeasonStandings,
getLastSyncedAt,
deleteRegularSeasonStandings,
getParticipantStanding,
} from "../regular-season-standings";
import { database } from "~/database/context";
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
function makeUpsertDb(returnedRows: object[] = []) {
const returning = vi.fn().mockResolvedValue(returnedRows);
const onConflictDoUpdate = vi.fn().mockReturnValue({ returning });
const values = vi.fn().mockReturnValue({ onConflictDoUpdate });
const insert = vi.fn().mockReturnValue({ values });
const db: Record<string, unknown> = {
insert,
transaction: vi.fn().mockImplementation(async (fn: (tx: unknown) => unknown) => fn(db)),
};
return { db, insert, values, onConflictDoUpdate, returning };
}
function makeRecord(overrides: Record<string, unknown> = {}) {
return {
participantId: "p-1",
sportsSeasonId: "ss-1",
wins: 10,
losses: 5,
gamesPlayed: 15,
...overrides,
};
}
beforeEach(() => {
vi.clearAllMocks();
});
// ---------------------------------------------------------------------------
// upsertRegularSeasonStandings
// ---------------------------------------------------------------------------
describe("upsertRegularSeasonStandings", () => {
it("returns empty array immediately when given no records", async () => {
const { db } = makeUpsertDb();
vi.mocked(database).mockReturnValue(db as never);
const result = await upsertRegularSeasonStandings([]);
expect(result).toEqual([]);
expect(db.insert).not.toHaveBeenCalled();
});
it("maps winPct and gamesBack to strings", async () => {
const { db, values } = makeUpsertDb([]);
vi.mocked(database).mockReturnValue(db as never);
await upsertRegularSeasonStandings([
makeRecord({ winPct: 0.667, gamesBack: 2.5 }),
]);
const inserted = values.mock.calls[0][0];
expect(inserted[0].winPct).toBe("0.667");
expect(inserted[0].gamesBack).toBe("2.5");
});
it("maps null winPct and gamesBack to null", async () => {
const { db, values } = makeUpsertDb([]);
vi.mocked(database).mockReturnValue(db as never);
await upsertRegularSeasonStandings([
makeRecord({ winPct: null, gamesBack: null }),
]);
const inserted = values.mock.calls[0][0];
expect(inserted[0].winPct).toBeNull();
expect(inserted[0].gamesBack).toBeNull();
});
it("uses the provided db instead of calling database()", async () => {
const { db } = makeUpsertDb([]);
await upsertRegularSeasonStandings([makeRecord()], db as never);
expect(database).not.toHaveBeenCalled();
expect(db.transaction).toHaveBeenCalled();
});
it("returns the rows from the DB", async () => {
const row = { id: "row-1", wins: 10 };
const { db } = makeUpsertDb([row]);
vi.mocked(database).mockReturnValue(db as never);
const result = await upsertRegularSeasonStandings([makeRecord()]);
expect(result).toEqual([row]);
});
it("inserts multiple records in a single call", async () => {
const { db, values } = makeUpsertDb([]);
vi.mocked(database).mockReturnValue(db as never);
await upsertRegularSeasonStandings([
makeRecord({ participantId: "p-1" }),
makeRecord({ participantId: "p-2" }),
]);
expect(values.mock.calls[0][0]).toHaveLength(2);
});
it("sets syncedAt to now when not provided", async () => {
const before = new Date();
const { db, values } = makeUpsertDb([]);
vi.mocked(database).mockReturnValue(db as never);
await upsertRegularSeasonStandings([makeRecord()]);
const inserted = values.mock.calls[0][0];
expect(inserted[0].syncedAt).toBeInstanceOf(Date);
expect(inserted[0].syncedAt.getTime()).toBeGreaterThanOrEqual(before.getTime());
});
});
// ---------------------------------------------------------------------------
// upsertManualStanding
// ---------------------------------------------------------------------------
describe("upsertManualStanding", () => {
it("sets syncedAt to null", async () => {
const { db, values } = makeUpsertDb([{ id: "row-1" }]);
vi.mocked(database).mockReturnValue(db as never);
await upsertManualStanding("p-1", "ss-1", {
wins: 10,
losses: 5,
gamesPlayed: 15,
});
const inserted = values.mock.calls[0][0];
expect(inserted[0].syncedAt).toBeNull();
});
it("returns the first row", async () => {
const row = { id: "row-1" };
const { db } = makeUpsertDb([row]);
vi.mocked(database).mockReturnValue(db as never);
const result = await upsertManualStanding("p-1", "ss-1", {
wins: 10,
losses: 5,
gamesPlayed: 15,
});
expect(result).toEqual(row);
});
});
// ---------------------------------------------------------------------------
// getRegularSeasonStandings — sorting logic
// ---------------------------------------------------------------------------
function makeRow(overrides: Record<string, unknown>) {
return {
conference: null,
division: null,
divisionRank: null,
leagueRank: null,
participant: {},
...overrides,
};
}
function makeQueryDb(rows: object[]) {
return {
query: {
regularSeasonStandings: {
findMany: vi.fn().mockResolvedValue(rows),
},
},
};
}
describe("getRegularSeasonStandings", () => {
it("sorts by conference alphabetically", async () => {
const rows = [
makeRow({ conference: "Western", leagueRank: 1 }),
makeRow({ conference: "Eastern", leagueRank: 2 }),
];
vi.mocked(database).mockReturnValue(makeQueryDb(rows) as never);
const result = await getRegularSeasonStandings("ss-1");
expect(result[0].conference).toBe("Eastern");
expect(result[1].conference).toBe("Western");
});
it("sorts by division within conference", async () => {
const rows = [
makeRow({ conference: "East", division: "Southeast", leagueRank: 1 }),
makeRow({ conference: "East", division: "Atlantic", leagueRank: 2 }),
];
vi.mocked(database).mockReturnValue(makeQueryDb(rows) as never);
const result = await getRegularSeasonStandings("ss-1");
expect(result[0].division).toBe("Atlantic");
expect(result[1].division).toBe("Southeast");
});
it("sorts by divisionRank within division", async () => {
const rows = [
makeRow({ conference: "East", division: "Atlantic", divisionRank: 3 }),
makeRow({ conference: "East", division: "Atlantic", divisionRank: 1 }),
makeRow({ conference: "East", division: "Atlantic", divisionRank: 2 }),
];
vi.mocked(database).mockReturnValue(makeQueryDb(rows) as never);
const result = await getRegularSeasonStandings("ss-1");
expect(result.map((r) => r.divisionRank)).toEqual([1, 2, 3]);
});
it("falls back to leagueRank when divisionRank is null", async () => {
const rows = [
makeRow({ leagueRank: 3 }),
makeRow({ leagueRank: 1 }),
makeRow({ leagueRank: 2 }),
];
vi.mocked(database).mockReturnValue(makeQueryDb(rows) as never);
const result = await getRegularSeasonStandings("ss-1");
expect(result.map((r) => r.leagueRank)).toEqual([1, 2, 3]);
});
it("places null conference/division rows last", async () => {
const rows = [
makeRow({ conference: null, leagueRank: 1 }),
makeRow({ conference: "Eastern", leagueRank: 2 }),
];
vi.mocked(database).mockReturnValue(makeQueryDb(rows) as never);
const result = await getRegularSeasonStandings("ss-1");
expect(result[0].conference).toBe("Eastern");
expect(result[1].conference).toBeNull();
});
});
// ---------------------------------------------------------------------------
// getLastSyncedAt
// ---------------------------------------------------------------------------
describe("getLastSyncedAt", () => {
function makeSelectDb(lastSync: Date | null) {
return {
select: vi.fn().mockReturnValue({
from: vi.fn().mockReturnValue({
where: vi.fn().mockResolvedValue([{ lastSync }]),
}),
}),
};
}
it("returns the max syncedAt date", async () => {
const date = new Date("2025-03-01T00:00:00Z");
vi.mocked(database).mockReturnValue(makeSelectDb(date) as never);
const result = await getLastSyncedAt("ss-1");
expect(result).toEqual(date);
});
it("returns null when no synced records exist", async () => {
vi.mocked(database).mockReturnValue(makeSelectDb(null) as never);
const result = await getLastSyncedAt("ss-1");
expect(result).toBeNull();
});
});
// ---------------------------------------------------------------------------
// deleteRegularSeasonStandings
// ---------------------------------------------------------------------------
describe("deleteRegularSeasonStandings", () => {
it("calls delete on the DB", async () => {
const where = vi.fn().mockResolvedValue(undefined);
const del = vi.fn().mockReturnValue({ where });
const db = { delete: del };
vi.mocked(database).mockReturnValue(db as never);
await deleteRegularSeasonStandings("ss-1");
expect(del).toHaveBeenCalled();
expect(where).toHaveBeenCalled();
});
});
// ---------------------------------------------------------------------------
// getParticipantStanding
// ---------------------------------------------------------------------------
describe("getParticipantStanding", () => {
it("returns the standing row when found", async () => {
const row = { id: "row-1", participantId: "p-1" };
const db = {
query: {
regularSeasonStandings: {
findFirst: vi.fn().mockResolvedValue(row),
},
},
};
vi.mocked(database).mockReturnValue(db as never);
const result = await getParticipantStanding("p-1", "ss-1");
expect(result).toEqual(row);
});
it("returns undefined when not found", async () => {
const db = {
query: {
regularSeasonStandings: {
findFirst: vi.fn().mockResolvedValue(undefined),
},
},
};
vi.mocked(database).mockReturnValue(db as never);
const result = await getParticipantStanding("p-99", "ss-1");
expect(result).toBeUndefined();
});
});