This commit is contained in:
@@ -0,0 +1,271 @@
|
||||
import { describe, it, expect, beforeAll, afterEach } from "vitest";
|
||||
import * as WeeklyXpLeaderboard from "../../../src/services/weekly-xp-leaderboard";
|
||||
import { Configuration } from "@monkeytype/schemas/configuration";
|
||||
import { ObjectId } from "mongodb";
|
||||
import { RedisXpLeaderboardEntry } from "@monkeytype/schemas/leaderboards";
|
||||
import { cleanupKeys, redisSetup } from "../redis";
|
||||
|
||||
const leaderboardsConfig: Configuration["leaderboards"]["weeklyXp"] = {
|
||||
enabled: true,
|
||||
expirationTimeInDays: 7,
|
||||
xpRewardBrackets: [],
|
||||
};
|
||||
|
||||
describe("Weekly XP Leaderboards", () => {
|
||||
beforeAll(async () => {
|
||||
await redisSetup();
|
||||
});
|
||||
afterEach(async () => {
|
||||
await cleanupKeys(WeeklyXpLeaderboard.__testing.namespace);
|
||||
});
|
||||
|
||||
describe("get", () => {
|
||||
it("should get if enabled", () => {
|
||||
expect(WeeklyXpLeaderboard.get(leaderboardsConfig)).toBeInstanceOf(
|
||||
WeeklyXpLeaderboard.WeeklyXpLeaderboard,
|
||||
);
|
||||
});
|
||||
it("should return null if disabled", () => {
|
||||
expect(WeeklyXpLeaderboard.get({ enabled: false } as any)).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("WeeklyXpLeaderboard class", () => {
|
||||
// oxlint-disable-next-line no-non-null-assertion
|
||||
const lb = WeeklyXpLeaderboard.get(leaderboardsConfig)!;
|
||||
|
||||
describe("addResult", () => {
|
||||
it("adds results for user", async () => {
|
||||
//GIVEN
|
||||
const user1 = await givenResult(100, { timeTypedSeconds: 5 });
|
||||
await givenResult(50, { ...user1, timeTypedSeconds: 5 });
|
||||
const user2 = await givenResult(100, {
|
||||
isPremium: true,
|
||||
timeTypedSeconds: 7,
|
||||
});
|
||||
|
||||
//WHEN
|
||||
const results = await lb.getResults(0, 10, leaderboardsConfig, true);
|
||||
|
||||
//THEN
|
||||
expect(results).toEqual({
|
||||
count: 2,
|
||||
entries: [
|
||||
{
|
||||
...user1,
|
||||
rank: 1,
|
||||
timeTypedSeconds: 10,
|
||||
totalXp: 150,
|
||||
isPremium: false,
|
||||
},
|
||||
{
|
||||
...user2,
|
||||
rank: 2,
|
||||
timeTypedSeconds: 7,
|
||||
totalXp: 100,
|
||||
isPremium: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("getResults", () => {
|
||||
it("gets results", async () => {
|
||||
//GIVEN
|
||||
const user1 = await givenResult(150);
|
||||
const user2 = await givenResult(100);
|
||||
|
||||
//WHEN
|
||||
const results = await lb.getResults(0, 10, leaderboardsConfig, true);
|
||||
|
||||
//THEN
|
||||
expect(results).toEqual({
|
||||
count: 2,
|
||||
entries: [
|
||||
{ rank: 1, totalXp: 150, ...user1 },
|
||||
{ rank: 2, totalXp: 100, ...user2 },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("gets results for page", async () => {
|
||||
//GIVEN
|
||||
const _user1 = await givenResult(100);
|
||||
const _user2 = await givenResult(75);
|
||||
const user3 = await givenResult(50);
|
||||
const user4 = await givenResult(25);
|
||||
|
||||
//WHEN
|
||||
const results = await lb.getResults(1, 2, leaderboardsConfig, true);
|
||||
|
||||
//THEN
|
||||
expect(results).toEqual({
|
||||
count: 4,
|
||||
entries: [
|
||||
{ rank: 3, totalXp: 50, ...user3 },
|
||||
{ rank: 4, totalXp: 25, ...user4 },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("gets results without premium", async () => {
|
||||
//GIVEN
|
||||
const user1 = await givenResult(150, { isPremium: true });
|
||||
const user2 = await givenResult(100);
|
||||
|
||||
//WHEN
|
||||
const results = await lb.getResults(0, 10, leaderboardsConfig, false);
|
||||
|
||||
//THEN
|
||||
expect(results).toEqual({
|
||||
count: 2,
|
||||
entries: [
|
||||
{ rank: 1, totalXp: 150, ...user1, isPremium: undefined },
|
||||
{ rank: 2, totalXp: 100, ...user2, isPremium: undefined },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("gets results for friends only", async () => {
|
||||
//GIVEN
|
||||
const _user1 = await givenResult(100);
|
||||
const user2 = await givenResult(75);
|
||||
const _user3 = await givenResult(50);
|
||||
const user4 = await givenResult(25);
|
||||
|
||||
//WHEN
|
||||
const results = await lb.getResults(0, 5, leaderboardsConfig, true, [
|
||||
user2.uid,
|
||||
user4.uid,
|
||||
new ObjectId().toHexString(),
|
||||
]);
|
||||
|
||||
//THEN
|
||||
expect(results).toEqual({
|
||||
count: 2,
|
||||
entries: [
|
||||
{ rank: 2, friendsRank: 1, totalXp: 75, ...user2 },
|
||||
{ rank: 4, friendsRank: 2, totalXp: 25, ...user4 },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("gets results for friends only with page", async () => {
|
||||
//GIVEN
|
||||
const user1 = await givenResult(100);
|
||||
const user2 = await givenResult(75);
|
||||
const _user3 = await givenResult(50);
|
||||
const user4 = await givenResult(25);
|
||||
const _user5 = await givenResult(5);
|
||||
|
||||
//WHEN
|
||||
const results = await lb.getResults(1, 2, leaderboardsConfig, true, [
|
||||
user1.uid,
|
||||
user2.uid,
|
||||
user4.uid,
|
||||
new ObjectId().toHexString(),
|
||||
]);
|
||||
|
||||
//THEN
|
||||
expect(results).toEqual({
|
||||
count: 3,
|
||||
entries: [{ rank: 4, friendsRank: 3, totalXp: 25, ...user4 }],
|
||||
});
|
||||
});
|
||||
|
||||
it("should return empty list if no friends", async () => {
|
||||
//GIVEN
|
||||
|
||||
//WHEN
|
||||
const results = await lb.getResults(0, 5, leaderboardsConfig, true, []);
|
||||
|
||||
//THEN
|
||||
expect(results).toEqual({
|
||||
count: 0,
|
||||
entries: [],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("getRank", () => {
|
||||
it("gets rank", async () => {
|
||||
//GIVEN
|
||||
const user1 = await givenResult(100);
|
||||
const _user2 = await givenResult(150);
|
||||
|
||||
//WHEN
|
||||
const rank = await lb.getRank(user1.uid, leaderboardsConfig);
|
||||
//THEN
|
||||
expect(rank).toEqual({ rank: 2, totalXp: 100, ...user1 });
|
||||
});
|
||||
|
||||
it("should return null for unknown user", async () => {
|
||||
expect(await lb.getRank("decoy", leaderboardsConfig)).toBeNull();
|
||||
expect(
|
||||
await lb.getRank("decoy", leaderboardsConfig, [
|
||||
"unknown",
|
||||
"unknown2",
|
||||
]),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
it("gets rank for friends", async () => {
|
||||
//GIVEN
|
||||
const user1 = await givenResult(50);
|
||||
const user2 = await givenResult(60);
|
||||
const _user3 = await givenResult(70);
|
||||
|
||||
const friends = [user1.uid, user2.uid, "decoy"];
|
||||
|
||||
//WHEN / THEN
|
||||
expect(
|
||||
await lb.getRank(user2.uid, leaderboardsConfig, friends),
|
||||
).toEqual({ rank: 2, friendsRank: 1, totalXp: 60, ...user2 });
|
||||
|
||||
expect(
|
||||
await lb.getRank(user1.uid, leaderboardsConfig, friends),
|
||||
).toEqual({ rank: 3, friendsRank: 2, totalXp: 50, ...user1 });
|
||||
});
|
||||
});
|
||||
|
||||
it("purgeUserFromDailyLeaderboards", async () => {
|
||||
//GIVEN
|
||||
const cheater = await givenResult(50);
|
||||
const validUser = await givenResult(1000);
|
||||
|
||||
//WHEN
|
||||
await WeeklyXpLeaderboard.purgeUserFromXpLeaderboards(
|
||||
cheater.uid,
|
||||
leaderboardsConfig,
|
||||
);
|
||||
//THEN
|
||||
expect(await lb.getRank(cheater.uid, leaderboardsConfig)).toBeNull();
|
||||
expect(await lb.getResults(0, 50, leaderboardsConfig, true)).toEqual({
|
||||
count: 1,
|
||||
entries: [{ rank: 1, totalXp: 1000, ...validUser }],
|
||||
});
|
||||
});
|
||||
|
||||
async function givenResult(
|
||||
xpGained: number,
|
||||
entry?: Partial<RedisXpLeaderboardEntry>,
|
||||
): Promise<RedisXpLeaderboardEntry> {
|
||||
const uid = new ObjectId().toHexString();
|
||||
const result: RedisXpLeaderboardEntry = {
|
||||
uid,
|
||||
name: `User ${uid}`,
|
||||
lastActivityTimestamp: Date.now(),
|
||||
timeTypedSeconds: 42,
|
||||
badgeId: 2,
|
||||
discordAvatar: `${uid}Avatar`,
|
||||
discordId: `${uid}DiscordId`,
|
||||
isPremium: false,
|
||||
...entry,
|
||||
};
|
||||
|
||||
await lb.addResult(leaderboardsConfig, { xpGained, entry: result });
|
||||
return result;
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user