mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2025-10-15 18:15:58 +08:00
test: add WeeklyXpLeaderboards integration tests (@fehmer) (#6843)
This commit is contained in:
parent
c8a91ede52
commit
cd99d5af16
5 changed files with 211 additions and 12 deletions
11
backend/__tests__/__integration__/redis.ts
Normal file
11
backend/__tests__/__integration__/redis.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { getConnection, connect } from "../../src/init/redis";
|
||||
|
||||
export async function redisSetup(): Promise<void> {
|
||||
await connect();
|
||||
}
|
||||
export async function cleanupKeys(prefix: string): Promise<void> {
|
||||
// oxlint-disable-next-line no-non-null-assertion
|
||||
const connection = getConnection()!;
|
||||
const keys = await connection.keys(`${prefix}*`);
|
||||
await Promise.all(keys?.map((it) => connection.del(it)));
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
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([
|
||||
{
|
||||
...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([
|
||||
{ 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([
|
||||
{ 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([
|
||||
{ rank: 1, totalXp: 150, ...user1, isPremium: undefined },
|
||||
{ rank: 2, totalXp: 100, ...user2, isPremium: undefined },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
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 });
|
||||
});
|
||||
});
|
||||
|
||||
describe("getCount", () => {
|
||||
it("gets count", async () => {
|
||||
//GIVEN
|
||||
await givenResult(100);
|
||||
await givenResult(150);
|
||||
|
||||
//WHEN
|
||||
const count = await lb.getCount();
|
||||
//THEN
|
||||
expect(count).toEqual(2);
|
||||
});
|
||||
});
|
||||
|
||||
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([
|
||||
{ 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;
|
||||
}
|
||||
});
|
||||
});
|
|
@ -1,12 +1,13 @@
|
|||
import { Mode, Mode2 } from "@monkeytype/schemas/shared";
|
||||
import * as DailyLeaderboards from "../../../src/utils/daily-leaderboards";
|
||||
import { getConnection, connect as redisSetup } from "../../../src/init/redis";
|
||||
import { cleanupKeys, redisSetup } from "../redis";
|
||||
import { Language } from "@monkeytype/schemas/languages";
|
||||
|
||||
import { RedisDailyLeaderboardEntry } from "@monkeytype/schemas/leaderboards";
|
||||
import { ObjectId } from "mongodb";
|
||||
import { Configuration } from "@monkeytype/schemas/configuration";
|
||||
|
||||
const dailyLeaderboardsConfig = {
|
||||
const dailyLeaderboardsConfig: Configuration["dailyLeaderboards"] = {
|
||||
enabled: true,
|
||||
maxResults: 10,
|
||||
leaderboardExpirationTimeInDays: 1,
|
||||
|
@ -32,7 +33,7 @@ describe("Daily Leaderboards", () => {
|
|||
await redisSetup();
|
||||
});
|
||||
afterEach(async () => {
|
||||
await getConnection()?.flushall();
|
||||
await cleanupKeys(DailyLeaderboards.__testing.namespace);
|
||||
});
|
||||
describe("should properly handle valid and invalid modes", () => {
|
||||
const testCases: {
|
||||
|
@ -256,8 +257,7 @@ describe("Daily Leaderboards", () => {
|
|||
it("purgeUserFromDailyLeaderboards", async () => {
|
||||
//GIVEN
|
||||
const cheater = await givenResult({ wpm: 50 });
|
||||
await givenResult({ wpm: 60 });
|
||||
await givenResult({ wpm: 40 });
|
||||
const validUser = await givenResult();
|
||||
|
||||
//WHEN
|
||||
await DailyLeaderboards.purgeUserFromDailyLeaderboards(
|
||||
|
@ -266,15 +266,13 @@ describe("Daily Leaderboards", () => {
|
|||
);
|
||||
//THEN
|
||||
expect(await lb.getRank(cheater.uid, dailyLeaderboardsConfig)).toBeNull();
|
||||
expect(
|
||||
(await lb.getResults(0, 50, dailyLeaderboardsConfig, false)).filter(
|
||||
(it) => it.uid === cheater.uid
|
||||
)
|
||||
).toEqual([]);
|
||||
expect(await lb.getResults(0, 50, dailyLeaderboardsConfig, true)).toEqual(
|
||||
[{ rank: 1, ...validUser }]
|
||||
);
|
||||
});
|
||||
|
||||
async function givenResult(
|
||||
entry: Partial<RedisDailyLeaderboardEntry>
|
||||
entry?: Partial<RedisDailyLeaderboardEntry>
|
||||
): Promise<RedisDailyLeaderboardEntry> {
|
||||
const uid = new ObjectId().toHexString();
|
||||
const result = {
|
||||
|
|
|
@ -13,7 +13,7 @@ import { omit } from "lodash";
|
|||
import { parseWithSchema as parseJsonWithSchema } from "@monkeytype/util/json";
|
||||
import { tryCatchSync } from "@monkeytype/util/trycatch";
|
||||
|
||||
type AddResultOpts = {
|
||||
export type AddResultOpts = {
|
||||
entry: RedisXpLeaderboardEntry;
|
||||
xpGained: RedisXpLeaderboardScore;
|
||||
};
|
||||
|
@ -285,3 +285,7 @@ export async function purgeUserFromXpLeaderboards(
|
|||
weeklyXpLeaderboardLeaderboardNamespace
|
||||
);
|
||||
}
|
||||
|
||||
export const __testing = {
|
||||
namespace: weeklyXpLeaderboardLeaderboardNamespace,
|
||||
};
|
||||
|
|
|
@ -298,3 +298,7 @@ export function getDailyLeaderboard(
|
|||
|
||||
return new DailyLeaderboard(modeRule, customTimestamp);
|
||||
}
|
||||
|
||||
export const __testing = {
|
||||
namespace: dailyLeaderboardNamespace,
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue