beatsaber-overlay/src/client/live-api.test.ts

78 lines
3.1 KiB
TypeScript

import { assert, assertEquals } from "jsr:@std/assert";
import {
fetchAllMapScoresByHash,
fetchBLLeaderboardsByHash,
fetchFriends,
normalizeAccuracy,
} from "./beatleader.ts";
import { fetchBeatSaverMapById } from "./beatsaver.ts";
const MAP_KEY = "4f4e4";
const PLAYER_ID = "76561199407393962";
const MODE = "Standard";
function normalizeDifficultyName(value: string | null | undefined) {
return (value ?? "").toLowerCase().replace(/\s+/g, "").replace("expert+", "expertplus");
}
function leaderboardId(lb: { id?: string | number | null; leaderboardId?: string | number | null }) {
const id = lb.id ?? lb.leaderboardId;
return id == null ? "" : String(id);
}
Deno.test({
name: "live lookup: map hash -> expertplus leaderboard -> mutual friend scores",
sanitizeOps: false,
sanitizeResources: false,
async fn() {
const map = await fetchBeatSaverMapById(MAP_KEY);
assert(map?.versions?.[0]?.hash, `BeatSaver map ${MAP_KEY} should resolve to a hash`);
const hash = String(map.versions[0].hash).toLowerCase();
const leaderboards = await fetchBLLeaderboardsByHash(hash);
assert(leaderboards.length > 0, "Expected BeatLeader leaderboards for hash");
const expertPlus = leaderboards.find((lb) => {
const modeOk = (lb.difficulty?.modeName ?? "").toLowerCase() === MODE.toLowerCase();
const diff = normalizeDifficultyName(lb.difficulty?.difficultyName);
return modeOk && diff === "expertplus";
});
assert(expertPlus, "Expected Standard ExpertPlus leaderboard");
const nonExpertPlus = leaderboards.find((lb) => {
const modeOk = (lb.difficulty?.modeName ?? "").toLowerCase() === MODE.toLowerCase();
const diff = normalizeDifficultyName(lb.difficulty?.difficultyName);
return modeOk && diff !== "expertplus";
});
assert(nonExpertPlus, "Expected a Standard non-ExpertPlus leaderboard");
assert(
leaderboardId(expertPlus) !== leaderboardId(nonExpertPlus),
"ExpertPlus should map to a different leaderboard id than another difficulty",
);
const mutualFriends = await fetchFriends(PLAYER_ID, "mutual", 100);
const mutualIds = new Set(mutualFriends.map((f) => f.id));
assert(mutualIds.size > 0, "Expected at least one mutual friend");
const [expertPlusScores, allMapScores] = await Promise.all([
fetchAllMapScoresByHash(hash, [expertPlus], 120),
fetchAllMapScoresByHash(hash, leaderboards, 120),
]);
assert(expertPlusScores.length > 0, "Expected some ExpertPlus scores");
assert(allMapScores.length > 0, "Expected map to have scores across leaderboards");
const mutualScores = allMapScores.filter((score) => {
const playerId = score.playerId ?? (typeof score.player === "object" ? score.player?.id : null);
return playerId != null && mutualIds.has(String(playerId));
});
assert(mutualScores.length > 0, "Expected at least one mutual friend score on this map");
const accuracies = mutualScores
.map((score) => normalizeAccuracy(score.accuracy ?? score.acc))
.filter((value): value is number => value !== null);
assert(accuracies.length > 0, "Expected mutual scores to include accuracy values");
assert(accuracies.some((acc) => acc > 0), "Expected positive accuracy values");
assertEquals(hash.length, 40);
},
});