Add unit tests for regular-season-standings model
Covers upsertRegularSeasonStandings (empty-array short-circuit, value mapping, syncedAt behaviour), upsertManualStanding, getRegularSeasonStandings sorting, getLastSyncedAt, deleteRegularSeasonStandings, and getParticipantStanding — 19 tests total. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
5b2407bec1
commit
93c06d372a
1 changed files with 333 additions and 0 deletions
333
app/models/__tests__/regular-season-standings.test.ts
Normal file
333
app/models/__tests__/regular-season-standings.test.ts
Normal file
|
|
@ -0,0 +1,333 @@
|
|||
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();
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue