tests
This commit is contained in:
parent
7609feead0
commit
ff733b9774
2 changed files with 59 additions and 4 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
import { describe, expect, it, vi } from "vitest";
|
import { describe, expect, it, vi } from "vitest";
|
||||||
import type { Question, QuizRound } from "../../party-types";
|
import type { Question, QuizRound } from "../../party-types";
|
||||||
|
import { buildAudioMetadataQuestion } from "../audio-question-generator";
|
||||||
import { buildNumericQuestion } from "../numeric-question-generator";
|
import { buildNumericQuestion } from "../numeric-question-generator";
|
||||||
import {
|
import {
|
||||||
buildMemberOptions,
|
buildMemberOptions,
|
||||||
|
|
@ -266,6 +267,50 @@ describe("question generation", () => {
|
||||||
expect(question).toBeNull();
|
expect(question).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("builds audio questions with fewer than four real options", async () => {
|
||||||
|
const randomSpy = vi.spyOn(Math, "random").mockReturnValue(0.99);
|
||||||
|
const db = createFakeDb(null);
|
||||||
|
const analytics = {
|
||||||
|
storyClusters: [
|
||||||
|
{
|
||||||
|
tracks: [
|
||||||
|
{
|
||||||
|
name: "Shared Track One",
|
||||||
|
artists: [{ name: "Shared Artist One" }],
|
||||||
|
albumName: "Shared Album One",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Shared Track Two",
|
||||||
|
artists: [{ name: "Shared Artist Two" }],
|
||||||
|
albumName: "Shared Album Two",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
artists: [
|
||||||
|
{ name: "Shared Artist One" },
|
||||||
|
{ name: "Shared Artist Two" },
|
||||||
|
],
|
||||||
|
genres: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
groupSummary: {
|
||||||
|
mostSharedGenres: [],
|
||||||
|
},
|
||||||
|
} as PartyAnalytics;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const question = await buildAudioMetadataQuestion(db, analytics, 0, []);
|
||||||
|
|
||||||
|
expect(question).not.toBeNull();
|
||||||
|
expect(question?.type).toBe("choice");
|
||||||
|
if (question?.type === "choice") {
|
||||||
|
expect(question.options).toHaveLength(2);
|
||||||
|
expect(question.text).toContain("Shared Track Two");
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
randomSpy.mockRestore();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it("selects a fresh party song when the current one was already used", async () => {
|
it("selects a fresh party song when the current one was already used", async () => {
|
||||||
const db = createSongFallbackDb([
|
const db = createSongFallbackDb([
|
||||||
makeSong("track-1", "spotify:track:one", "One"),
|
makeSong("track-1", "spotify:track:one", "One"),
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@ export function getMostSharedGenreNames(analytics: PartyAnalytics): string[] {
|
||||||
export function pickQuestionCandidate<T extends QuestionLike>(
|
export function pickQuestionCandidate<T extends QuestionLike>(
|
||||||
candidates: QuestionCandidate<T>[],
|
candidates: QuestionCandidate<T>[],
|
||||||
history: QuizRound[],
|
history: QuizRound[],
|
||||||
index: number,
|
_index: number,
|
||||||
): T | null {
|
): T | null {
|
||||||
const seenKeys = new Set<string>();
|
const seenKeys = new Set<string>();
|
||||||
const seenSubjects = new Set<string>();
|
const seenSubjects = new Set<string>();
|
||||||
|
|
@ -165,7 +165,7 @@ export function pickQuestionCandidate<T extends QuestionLike>(
|
||||||
|
|
||||||
if (fresh.length === 0) return null;
|
if (fresh.length === 0) return null;
|
||||||
const pool = fresh;
|
const pool = fresh;
|
||||||
const candidate = pool[index % pool.length];
|
const candidate = pickRandom(pool);
|
||||||
if (!candidate) return null;
|
if (!candidate) return null;
|
||||||
return {
|
return {
|
||||||
...candidate.question,
|
...candidate.question,
|
||||||
|
|
@ -510,7 +510,8 @@ export function buildOrderedOptions(
|
||||||
const options = uniqueStrings(
|
const options = uniqueStrings(
|
||||||
values.filter((value): value is string => isUsableText(value)),
|
values.filter((value): value is string => isUsableText(value)),
|
||||||
);
|
);
|
||||||
return options.length >= desiredCount ? options.slice(0, desiredCount) : null;
|
const optionCount = getAvailableOptionCount(options.length, desiredCount);
|
||||||
|
return optionCount ? options.slice(0, optionCount) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildOptionsWithCorrect(
|
export function buildOptionsWithCorrect(
|
||||||
|
|
@ -523,7 +524,8 @@ export function buildOptionsWithCorrect(
|
||||||
correct,
|
correct,
|
||||||
...candidates.filter((c) => isUsableText(c) && c !== correct),
|
...candidates.filter((c) => isUsableText(c) && c !== correct),
|
||||||
]);
|
]);
|
||||||
return options.length >= desiredCount ? options.slice(0, desiredCount) : null;
|
const optionCount = getAvailableOptionCount(options.length, desiredCount);
|
||||||
|
return optionCount ? options.slice(0, optionCount) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function pickRandom<T>(items: T[]): T | null {
|
export function pickRandom<T>(items: T[]): T | null {
|
||||||
|
|
@ -532,6 +534,14 @@ export function pickRandom<T>(items: T[]): T | null {
|
||||||
return items[index] ?? null;
|
return items[index] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getAvailableOptionCount(
|
||||||
|
availableCount: number,
|
||||||
|
desiredCount: number,
|
||||||
|
): number | null {
|
||||||
|
if (availableCount < 2) return null;
|
||||||
|
return Math.min(availableCount, desiredCount);
|
||||||
|
}
|
||||||
|
|
||||||
export function getCurrentLeader(
|
export function getCurrentLeader(
|
||||||
quizState: { scores: Record<string, number> },
|
quizState: { scores: Record<string, number> },
|
||||||
members: PartyQuestionMember[],
|
members: PartyQuestionMember[],
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue