Files
buzz-sheet/lib/guides/queries.test.ts
T

134 lines
5.9 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from "vitest";
const mocks = vi.hoisted(() => ({ reads: [] as unknown[], rows: new Map<unknown, unknown[]>() }));
vi.mock("server-only", () => ({}));
vi.mock("@/lib/media/storage", () => ({ publicMediaUrl: (key: string) => `/media/${key}` }));
vi.mock("@/db", () => ({
getDb: () => ({
select: () => {
let table: unknown;
const query = {
from(value: unknown) { table = value; return query; },
innerJoin() { return query; },
leftJoin() { return query; },
where() { return query; },
orderBy() { return query; },
limit() { return query; },
then(resolve: (rows: unknown[]) => unknown) {
mocks.reads.push(table);
return Promise.resolve(mocks.rows.get(table) ?? []).then(resolve);
},
};
return query;
},
}),
}));
import {
artifactConditions, artifactProfiles, constellationConditions, extraSectionRows,
guides, guideSections, teamCompositions, teamConditions, teamMembers, weaponConditions,
catalogMaterials, guidePosterBleeding, media,
} from "@/db/schema";
import { getAdminGuideContent, listAdminTeamImportsForCharacter } from "./queries";
beforeEach(() => {
mocks.reads.length = 0;
mocks.rows.clear();
mocks.rows.set(guides, [{
guide: { id: "guide", slug: "test", posterArtMediaId: null },
cover: { objectKey: "cover", status: "ready" },
character: { key: "test", imageKey: "character", constellations: [], talents: [], ascension: [], leveling: [] },
}]);
mocks.rows.set(guideSections, [
{ id: "extra-a", slug: "extra-a", kind: "extra" },
{ id: "extra-b", slug: "extra-b", kind: "extra" },
]);
});
describe("admin section reads", () => {
it.each([
["weapon", weaponConditions],
["artifact", artifactConditions],
["constellations", constellationConditions],
["team", teamConditions],
])("loads only the %s section's conditions", async (section, expectedTable) => {
const result = await getAdminGuideContent("test", section);
expect(result).not.toBeNull();
expect(mocks.reads).toContain(expectedTable);
for (const table of [weaponConditions, artifactConditions, constellationConditions, teamConditions]) {
if (table !== expectedTable) expect(mocks.reads).not.toContain(table);
}
expect(mocks.reads).not.toContain(extraSectionRows);
expect(mocks.reads).not.toContain(catalogMaterials);
expect(mocks.reads).not.toContain(guidePosterBleeding);
});
it("loads just the selected extra section", async () => {
const result = await getAdminGuideContent("test", "extra-b");
expect(result?.extras.map((extra) => extra.id)).toEqual(["extra-b"]);
expect(mocks.reads).toContain(extraSectionRows);
expect(mocks.reads).not.toContain(weaponConditions);
expect(mocks.reads).not.toContain(teamConditions);
});
it("preserves full-guide reads for existing preview and validation callers", async () => {
const result = await getAdminGuideContent("test");
for (const table of [weaponConditions, artifactConditions, constellationConditions, teamConditions, extraSectionRows]) {
expect(mocks.reads).toContain(table);
}
expect(result?.extras).toHaveLength(2);
});
it("resolves condition icons from one batched media read", async () => {
const iconMediaId = "550e8400-e29b-41d4-a716-446655440000";
mocks.rows.set(weaponConditions, [{ id: "weapon-condition", iconMediaId }]);
mocks.rows.set(artifactConditions, [{ id: "artifact-condition", iconMediaId }]);
mocks.rows.set(constellationConditions, [{ id: "constellation-condition", iconMediaId }]);
mocks.rows.set(teamConditions, [{ id: "team-condition", iconMediaId }]);
mocks.rows.set(artifactProfiles, [{
sands: [], goblet: [], circlet: [], substats: [], targets: [],
recommendedConditions: [{ name: "Recommended", note: null, iconMediaId, sands: [], goblet: [], circlet: [], substats: [] }],
targetConditions: [{ name: "Target", note: null, iconMediaId, rows: [] }],
}]);
mocks.rows.set(media, [{ id: iconMediaId, objectKey: "condition-icon.png" }]);
const result = await getAdminGuideContent("test");
expect(result?.weaponGroups[0].iconUrl).toBe("/media/condition-icon.png");
expect(result?.artifactGroups[0].iconUrl).toBe("/media/condition-icon.png");
expect(result?.constellationGroups[0].iconUrl).toBe("/media/condition-icon.png");
expect(result?.teamGroups[0].iconUrl).toBe("/media/condition-icon.png");
expect(result?.artifactProfile?.recommendedConditions[0].iconUrl).toBe("/media/condition-icon.png");
expect(result?.artifactProfile?.targetConditions[0].iconUrl).toBe("/media/condition-icon.png");
expect(mocks.reads.filter((table) => table === media)).toHaveLength(1);
});
});
describe("team import lookup", () => {
it("hydrates matching teams and source labels with one member read", async () => {
mocks.rows.set(teamCompositions, [{
id: "team-1", title: "Example", rotationSeconds: "20", combo: "E > Q",
guideName: "Other Guide", conditionName: "Boss",
}]);
mocks.rows.set(teamMembers, [{
member: {
teamId: "team-1", characterKey: "character-1", weaponKey: "weapon-1",
artifactKey: "artifact-1", secondArtifactKey: null,
constellation: "2", refinement: "1", damage: "100",
},
characterName: "Character One",
}]);
const result = await listAdminTeamImportsForCharacter("current-guide", "character-1");
expect(result).toEqual([{
id: "team-1", title: "Example", rotationSeconds: "20", combo: "E > Q",
guideName: "Other Guide", conditionName: "Boss",
members: [{
characterKey: "character-1", characterName: "Character One", weaponKey: "weapon-1",
artifactKey: "artifact-1", secondArtifactKey: null,
constellation: "2", refinement: "1", damage: "100",
}],
}]);
expect(mocks.reads).toEqual([teamCompositions, teamMembers]);
});
});