import { describe, it, expect, beforeEach, afterEach, vi } from "vitest"; import { setup } from "../../__testData__/controller-test"; import { ObjectId } from "mongodb"; import * as LeaderboardDal from "../../../src/dal/leaderboards"; import * as ConnectionsDal from "../../../src/dal/connections"; import * as DailyLeaderboards from "../../../src/utils/daily-leaderboards"; import * as WeeklyXpLeaderboard from "../../../src/services/weekly-xp-leaderboard"; import * as Configuration from "../../../src/init/configuration"; import { mockAuthenticateWithApeKey } from "../../__testData__/auth"; import { XpLeaderboardEntry } from "@monkeytype/schemas/leaderboards"; const { mockApp, uid } = setup(); const configuration = Configuration.getCachedConfiguration(); const allModes = [ "10", "25", "50", "100", "15", "30", "60", "120", "zen", "custom", ]; describe("Loaderboard Controller", () => { describe("get leaderboard", () => { const getLeaderboardMock = vi.spyOn(LeaderboardDal, "get"); const getLeaderboardCountMock = vi.spyOn(LeaderboardDal, "getCount"); beforeEach(() => { getLeaderboardMock.mockClear(); getLeaderboardCountMock.mockClear(); getLeaderboardCountMock.mockResolvedValue(42); }); it("should get for english time 60", async () => { //GIVEN const resultData = { count: 42, pageSize: 50, entries: [ { wpm: 20, acc: 90, timestamp: 1000, raw: 92, consistency: 80, uid: "user1", name: "user1", discordId: "discordId", discordAvatar: "discordAvatar", rank: 1, badgeId: 1, isPremium: true, }, { wpm: 10, acc: 80, timestamp: 1200, raw: 82, uid: "user2", name: "user2", rank: 2, }, ], }; const mockData = resultData.entries.map((it) => ({ ...it, _id: new ObjectId(), })); getLeaderboardMock.mockResolvedValue(mockData); getLeaderboardCountMock.mockResolvedValue(42); //WHEN const { body } = await mockApp .get("/leaderboards") .query({ language: "english", mode: "time", mode2: "60" }) .expect(200); //THEN expect(body).toEqual({ message: "Leaderboard retrieved", data: resultData, }); expect(getLeaderboardMock).toHaveBeenCalledWith( "time", "60", "english", 0, 50, false, undefined, ); expect(getLeaderboardCountMock).toHaveBeenCalledWith( "time", "60", "english", undefined, ); }); it("should get for english time 60 with page", async () => { //GIVEN getLeaderboardMock.mockResolvedValue([]); getLeaderboardCountMock.mockResolvedValue(0); const page = 0; const pageSize = 25; //WHEN const { body } = await mockApp .get("/leaderboards") .query({ language: "english", mode: "time", mode2: "60", page, pageSize, }) .expect(200); //THEN expect(body).toEqual({ message: "Leaderboard retrieved", data: { count: 0, pageSize: 25, entries: [], }, }); expect(getLeaderboardMock).toHaveBeenCalledWith( "time", "60", "english", page, pageSize, false, undefined, ); }); it("should get for friendsOnly", async () => { //GIVEN await enableConnectionsFeature(true); getLeaderboardMock.mockResolvedValue([]); getLeaderboardCountMock.mockResolvedValue(2); //WHEN const { body } = await mockApp .get("/leaderboards") .set("Authorization", `Bearer ${uid}`) .query({ language: "english", mode: "time", mode2: "60", friendsOnly: true, }) .expect(200); //THEN expect(body.data.count).toEqual(2); expect(getLeaderboardMock).toHaveBeenCalledWith( "time", "60", "english", 0, 50, false, uid, ); expect(getLeaderboardCountMock).toHaveBeenCalledWith( "time", "60", "english", uid, ); }); describe("should get for modes", async () => { beforeEach(() => { getLeaderboardMock.mockResolvedValue([]); }); const testCases = [ { mode: "time", mode2: "15", language: "english", expectStatus: 200 }, { mode: "time", mode2: "60", language: "english", expectStatus: 200 }, { mode: "time", mode2: "30", language: "english", expectStatus: 404 }, { mode: "words", mode2: "15", language: "english", expectStatus: 404 }, { mode: "time", mode2: "15", language: "spanish", expectStatus: 404 }, ]; it.for(testCases)( `expect $expectStatus for mode $mode, mode2 $mode2, lang $language`, async ({ mode, mode2, language, expectStatus }) => { await mockApp .get("/leaderboards") .query({ language, mode, mode2 }) .expect(expectStatus); }, ); }); it("fails for missing query", async () => { const { body } = await mockApp.get("/leaderboards").expect(422); expect(body).toEqual({ message: "Invalid query schema", validationErrors: [ '"language" Required', '"mode" Required', '"mode2" Needs to be either a number, "zen" or "custom".', ], }); }); it("fails for invalid query", async () => { const { body } = await mockApp .get("/leaderboards") .query({ language: "en?gli.sh", mode: "unknownMode", mode2: "unknownMode2", page: -1, pageSize: 500, }) .expect(422); expect(body).toEqual({ message: "Invalid query schema", validationErrors: [ '"language" Invalid enum value. Must be a supported language', `"mode" Invalid enum value. Expected 'time' | 'words' | 'quote' | 'custom' | 'zen', received 'unknownMode'`, '"mode2" Needs to be a number or a number represented as a string e.g. "10".', '"page" Number must be greater than or equal to 0', '"pageSize" Number must be less than or equal to 200', ], }); }); it("fails for unknown query", async () => { const { body } = await mockApp .get("/leaderboards") .query({ language: "english", mode: "time", mode2: "60", extra: "value", }) .expect(422); expect(body).toEqual({ message: "Invalid query schema", validationErrors: ["Unrecognized key(s) in object: 'extra'"], }); }); it("fails while leaderboard is updating", async () => { //GIVEN getLeaderboardMock.mockResolvedValue(false); //WHEN const { body } = await mockApp .get("/leaderboards") .query({ language: "english", mode: "time", mode2: "60", }) .expect(503); expect(body.message).toEqual( "Leaderboard is currently updating. Please try again in a few seconds.", ); }); }); describe("get rank", () => { const getLeaderboardRankMock = vi.spyOn(LeaderboardDal, "getRank"); afterEach(() => { getLeaderboardRankMock.mockClear(); }); it("fails withouth authentication", async () => { await mockApp .get("/leaderboards/rank") .query({ language: "english", mode: "time", mode2: "60" }) .expect(401); }); it("should get for english time 60", async () => { //GIVEN const entryId = new ObjectId(); const resultEntry = { _id: entryId, wpm: 10, acc: 80, timestamp: 1200, raw: 82, uid: "user2", name: "user2", rank: 2, }; getLeaderboardRankMock.mockResolvedValue(resultEntry); //WHEN const { body } = await mockApp .get("/leaderboards/rank") .query({ language: "english", mode: "time", mode2: "60" }) .set("Authorization", `Bearer ${uid}`) .expect(200); //THEN expect(body).toEqual({ message: "Rank retrieved", data: { ...resultEntry, _id: undefined }, }); expect(getLeaderboardRankMock).toHaveBeenCalledWith( "time", "60", "english", uid, false, ); }); it("should get for english time 60 friends only", async () => { //GIVEN await enableConnectionsFeature(true); getLeaderboardRankMock.mockResolvedValue({} as any); //WHEN await mockApp .get("/leaderboards/rank") .query({ language: "english", mode: "time", mode2: "60", friendsOnly: true, }) .set("Authorization", `Bearer ${uid}`) .expect(200); //THEN expect(getLeaderboardRankMock).toHaveBeenCalledWith( "time", "60", "english", uid, true, ); }); it("should get null if no rank", async () => { //GIVEN await enableConnectionsFeature(true); getLeaderboardRankMock.mockResolvedValue(null); //WHEN const { body } = await mockApp .get("/leaderboards/rank") .query({ language: "english", mode: "time", mode2: "60", friendsOnly: true, }) .set("Authorization", `Bearer ${uid}`) .expect(200); //THEN expect(getLeaderboardRankMock).toHaveBeenCalledWith( "time", "60", "english", uid, true, ); expect(body).toEqual({ message: "Rank retrieved", data: null, }); }); it("should get with ape key", async () => { await acceptApeKeys(true); const apeKey = await mockAuthenticateWithApeKey(uid, await configuration); await mockApp .get("/leaderboards/rank") .query({ language: "english", mode: "time", mode2: "60" }) .set("authorization", "ApeKey " + apeKey) .expect(200); }); it("should get for mode", async () => { getLeaderboardRankMock.mockResolvedValue({} as any); for (const mode of ["time", "words", "quote", "zen", "custom"]) { const response = await mockApp .get("/leaderboards/rank") .set("Authorization", `Bearer ${uid}`) .query({ language: "english", mode, mode2: "custom" }); expect(response.status, "for mode " + mode).toEqual(200); } }); it("should get for mode2", async () => { getLeaderboardRankMock.mockResolvedValue({} as any); for (const mode2 of allModes) { const response = await mockApp .get("/leaderboards/rank") .set("Authorization", `Bearer ${uid}`) .query({ language: "english", mode: "words", mode2 }); expect(response.status, "for mode2 " + mode2).toEqual(200); } }); it("fails for missing query", async () => { const { body } = await mockApp .get("/leaderboards/rank") .set("Authorization", `Bearer ${uid}`) .expect(422); expect(body).toEqual({ message: "Invalid query schema", validationErrors: [ '"language" Required', '"mode" Required', '"mode2" Needs to be either a number, "zen" or "custom".', ], }); }); it("fails for invalid query", async () => { const { body } = await mockApp .get("/leaderboards/rank") .query({ language: "en?gli.sh", mode: "unknownMode", mode2: "unknownMode2", }) .set("Authorization", `Bearer ${uid}`) .expect(422); expect(body).toEqual({ message: "Invalid query schema", validationErrors: [ '"language" Invalid enum value. Must be a supported language', `"mode" Invalid enum value. Expected 'time' | 'words' | 'quote' | 'custom' | 'zen', received 'unknownMode'`, '"mode2" Needs to be a number or a number represented as a string e.g. "10".', ], }); }); it("fails for unknown query", async () => { const { body } = await mockApp .get("/leaderboards/rank") .query({ language: "english", mode: "time", mode2: "60", extra: "value", }) .set("Authorization", `Bearer ${uid}`) .expect(422); expect(body).toEqual({ message: "Invalid query schema", validationErrors: ["Unrecognized key(s) in object: 'extra'"], }); }); it("fails while leaderboard is updating", async () => { //GIVEN getLeaderboardRankMock.mockResolvedValue(false); //WHEN const { body } = await mockApp .get("/leaderboards/rank") .query({ language: "english", mode: "time", mode2: "60", }) .set("Authorization", `Bearer ${uid}`) .expect(503); expect(body.message).toEqual( "Leaderboard is currently updating. Please try again in a few seconds.", ); }); }); describe("get daily leaderboard", () => { const getDailyLeaderboardMock = vi.spyOn( DailyLeaderboards, "getDailyLeaderboard", ); const getFriendsUidsMock = vi.spyOn(ConnectionsDal, "getFriendsUids"); const getResultMock = vi.fn(); beforeEach(async () => { [getDailyLeaderboardMock, getFriendsUidsMock, getResultMock].forEach( (it) => it.mockClear(), ); vi.useFakeTimers(); vi.setSystemTime(1722606812000); await dailyLeaderboardEnabled(true); getDailyLeaderboardMock.mockReturnValue({ getResults: getResultMock, } as any); getResultMock.mockResolvedValue(null); }); afterEach(() => { vi.useRealTimers(); }); it("should get for english time 60", async () => { //GIVEN const lbConf = (await configuration).dailyLeaderboards; const premiumEnabled = (await configuration).users.premium.enabled; const resultData = { minWpm: 10, entries: [ { name: "user1", rank: 1, wpm: 20, acc: 90, timestamp: 1000, raw: 92, consistency: 80, uid: "user1", discordId: "discordId", discordAvatar: "discordAvatar", }, { wpm: 10, rank: 2, acc: 80, timestamp: 1200, raw: 82, consistency: 72, uid: "user2", name: "user2", }, ], }; getResultMock.mockResolvedValue({ count: 2, minWpm: 10, entries: resultData, }); //WHEN const { body } = await mockApp .get("/leaderboards/daily") .query({ language: "english", mode: "time", mode2: "60" }) .expect(200); //THEN expect(body).toEqual({ message: "Daily leaderboard retrieved", data: { count: 2, pageSize: 50, minWpm: 10, entries: resultData, }, }); expect(getDailyLeaderboardMock).toHaveBeenCalledWith( "english", "time", "60", lbConf, -1, ); expect(getResultMock).toHaveBeenCalledWith( 0, 50, lbConf, premiumEnabled, undefined, ); }); it("should get for english time 60 for yesterday", async () => { //GIVEN const lbConf = (await configuration).dailyLeaderboards; //WHEN const { body } = await mockApp .get("/leaderboards/daily") .query({ language: "english", mode: "time", mode2: "60", daysBefore: 1, }) .expect(200); //THEN expect(body).toEqual({ message: "Daily leaderboard retrieved", data: { entries: [], count: 0, pageSize: 50, minWpm: 0, }, }); expect(getDailyLeaderboardMock).toHaveBeenCalledWith( "english", "time", "60", lbConf, 1722470400000, ); }); it("should get for english time 60 with page and pageSize", async () => { //GIVEN const lbConf = (await configuration).dailyLeaderboards; const premiumEnabled = (await configuration).users.premium.enabled; const page = 2; const pageSize = 25; getResultMock.mockResolvedValue({ entries: [] }); //WHEN const { body } = await mockApp .get("/leaderboards/daily") .query({ language: "english", mode: "time", mode2: "60", page, pageSize, }) .expect(200); //THEN expect(body).toEqual({ message: "Daily leaderboard retrieved", data: { entries: [], count: 0, pageSize, minWpm: 0, }, }); expect(getDailyLeaderboardMock).toHaveBeenCalledWith( "english", "time", "60", lbConf, -1, ); expect(getResultMock).toHaveBeenCalledWith( page, pageSize, lbConf, premiumEnabled, undefined, ); }); it("should get for friends", async () => { //GIVEN const lbConf = (await configuration).dailyLeaderboards; const premiumEnabled = (await configuration).users.premium.enabled; await enableConnectionsFeature(true); const friends = [ new ObjectId().toHexString(), new ObjectId().toHexString(), ]; getFriendsUidsMock.mockResolvedValue(friends); //WHEN await mockApp .get("/leaderboards/daily") .set("Authorization", `Bearer ${uid}`) .query({ language: "english", mode: "time", mode2: "60", friendsOnly: true, }) .expect(200); //THEN expect(getDailyLeaderboardMock).toHaveBeenCalledWith( "english", "time", "60", lbConf, -1, ); expect(getResultMock).toHaveBeenCalledWith( 0, 50, lbConf, premiumEnabled, friends, ); }); it("fails for daysBefore not one", async () => { const { body } = await mockApp .get("/leaderboards/daily") .query({ language: "english", mode: "time", mode2: "60", daysBefore: 2, }) .expect(422); expect(body).toEqual({ message: "Invalid query schema", validationErrors: ['"daysBefore" Invalid literal value, expected 1'], }); }); it("fails if daily leaderboards are disabled", async () => { await dailyLeaderboardEnabled(false); const { body } = await mockApp.get("/leaderboards/daily").expect(503); expect(body.message).toEqual( "Daily leaderboards are not available at this time.", ); }); it("should get for mode", async () => { for (const mode of ["time", "words", "quote", "zen", "custom"]) { const response = await mockApp .get("/leaderboards/daily") .query({ language: "english", mode, mode2: "custom" }); expect(response.status, "for mode " + mode).toEqual(200); } }); it("should get for mode2", async () => { for (const mode2 of allModes) { const response = await mockApp .get("/leaderboards/daily") .query({ language: "english", mode: "words", mode2 }); expect(response.status, "for mode2 " + mode2).toEqual(200); } }); it("fails for missing query", async () => { const { body } = await mockApp.get("/leaderboards").expect(422); expect(body).toEqual({ message: "Invalid query schema", validationErrors: [ '"language" Required', '"mode" Required', '"mode2" Needs to be either a number, "zen" or "custom".', ], }); }); it("fails for invalid query", async () => { const { body } = await mockApp .get("/leaderboards/daily") .query({ language: "en?gli.sh", mode: "unknownMode", mode2: "unknownMode2", }) .expect(422); expect(body).toEqual({ message: "Invalid query schema", validationErrors: [ '"language" Invalid enum value. Must be a supported language', `"mode" Invalid enum value. Expected 'time' | 'words' | 'quote' | 'custom' | 'zen', received 'unknownMode'`, '"mode2" Needs to be a number or a number represented as a string e.g. "10".', ], }); }); it("fails for unknown query", async () => { const { body } = await mockApp .get("/leaderboards/daily") .query({ language: "english", mode: "time", mode2: "60", extra: "value", }) .expect(422); expect(body).toEqual({ message: "Invalid query schema", validationErrors: ["Unrecognized key(s) in object: 'extra'"], }); }); it("fails while leaderboard is missing", async () => { //GIVEN getDailyLeaderboardMock.mockReturnValue(null); //WHEN const { body } = await mockApp .get("/leaderboards/daily") .query({ language: "english", mode: "time", mode2: "60", }) .expect(404); expect(body.message).toEqual( "There is no daily leaderboard for this mode", ); }); }); describe("get daily leaderboard rank", () => { const getDailyLeaderboardMock = vi.spyOn( DailyLeaderboards, "getDailyLeaderboard", ); const getRankMock = vi.fn(); const getFriendsUidsMock = vi.spyOn(ConnectionsDal, "getFriendsUids"); beforeEach(async () => { [getDailyLeaderboardMock, getRankMock, getFriendsUidsMock].forEach((it) => it.mockClear(), ); getDailyLeaderboardMock.mockReturnValue({ getRank: getRankMock, } as any); vi.useFakeTimers(); vi.setSystemTime(1722606812000); await dailyLeaderboardEnabled(true); }); afterEach(() => { vi.useRealTimers(); }); it("fails withouth authentication", async () => { await mockApp .get("/leaderboards/daily/rank") .query({ language: "english", mode: "time", mode2: "60" }) .expect(401); }); it("should get for english time 60", async () => { //GIVEN const lbConf = (await configuration).dailyLeaderboards; const rankData = { min: 100, count: 1000, rank: 12, entry: { wpm: 10, rank: 2, acc: 80, timestamp: 1200, raw: 82, consistency: 72, uid: "user2", name: "user2", }, }; getRankMock.mockResolvedValue(rankData); //WHEN const { body } = await mockApp .get("/leaderboards/daily/rank") .set("Authorization", `Bearer ${uid}`) .query({ language: "english", mode: "time", mode2: "60" }) .expect(200); //THEN expect(body).toEqual({ message: "Daily leaderboard rank retrieved", data: rankData, }); expect(getDailyLeaderboardMock).toHaveBeenCalledWith( "english", "time", "60", lbConf, -1, ); expect(getRankMock).toHaveBeenCalledWith(uid, lbConf, undefined); }); it("should get for english time 60 friends only", async () => { //GIVEN await enableConnectionsFeature(true); const lbConf = (await configuration).dailyLeaderboards; getRankMock.mockResolvedValue({}); const friends = ["friendOne", "friendTwo"]; getFriendsUidsMock.mockResolvedValue(friends); //WHEN await mockApp .get("/leaderboards/daily/rank") .set("Authorization", `Bearer ${uid}`) .query({ language: "english", mode: "time", mode2: "60", friendsOnly: true, }) .expect(200); //THEN expect(getDailyLeaderboardMock).toHaveBeenCalledWith( "english", "time", "60", lbConf, -1, ); expect(getRankMock).toHaveBeenCalledWith(uid, lbConf, friends); expect(getFriendsUidsMock).toHaveBeenCalledWith(uid); }); it("fails if daily leaderboards are disabled", async () => { await dailyLeaderboardEnabled(false); const { body } = await mockApp .get("/leaderboards/daily/rank") .set("Authorization", `Bearer ${uid}`) .expect(503); expect(body.message).toEqual( "Daily leaderboards are not available at this time.", ); }); it("should get for mode", async () => { for (const mode of ["time", "words", "quote", "zen", "custom"]) { const response = await mockApp .get("/leaderboards/daily/rank") .set("Authorization", `Bearer ${uid}`) .query({ language: "english", mode, mode2: "custom" }); expect(response.status, "for mode " + mode).toEqual(200); } }); it("should get for mode2", async () => { for (const mode2 of allModes) { const response = await mockApp .get("/leaderboards/daily/rank") .set("Authorization", `Bearer ${uid}`) .query({ language: "english", mode: "words", mode2 }); expect(response.status, "for mode2 " + mode2).toEqual(200); } }); it("fails for missing query", async () => { const { body } = await mockApp .get("/leaderboards/daily/rank") .set("Authorization", `Bearer ${uid}`) .expect(422); expect(body).toEqual({ message: "Invalid query schema", validationErrors: [ '"language" Required', '"mode" Required', '"mode2" Needs to be either a number, "zen" or "custom".', ], }); }); it("fails for invalid query", async () => { const { body } = await mockApp .get("/leaderboards/daily/rank") .query({ language: "en?gli.sh", mode: "unknownMode", mode2: "unknownMode2", }) .set("Authorization", `Bearer ${uid}`) .expect(422); expect(body).toEqual({ message: "Invalid query schema", validationErrors: [ '"language" Invalid enum value. Must be a supported language', `"mode" Invalid enum value. Expected 'time' | 'words' | 'quote' | 'custom' | 'zen', received 'unknownMode'`, '"mode2" Needs to be a number or a number represented as a string e.g. "10".', ], }); }); it("fails for unknown query", async () => { const { body } = await mockApp .get("/leaderboards/daily/rank") .query({ language: "english", mode: "time", mode2: "60", extra: "value", }) .set("Authorization", `Bearer ${uid}`) .expect(422); expect(body).toEqual({ message: "Invalid query schema", validationErrors: ["Unrecognized key(s) in object: 'extra'"], }); }); it("fails while leaderboard is missing", async () => { //GIVEN getDailyLeaderboardMock.mockReturnValue(null); //WHEN const { body } = await mockApp .get("/leaderboards/daily/rank") .set("Authorization", `Bearer ${uid}`) .query({ language: "english", mode: "time", mode2: "60", }) .expect(404); expect(body.message).toEqual( "There is no daily leaderboard for this mode", ); }); }); describe("get xp weekly leaderboard", () => { const getXpWeeklyLeaderboardMock = vi.spyOn(WeeklyXpLeaderboard, "get"); const getResultMock = vi.fn(); const getFriendsUidsMock = vi.spyOn(ConnectionsDal, "getFriendsUids"); beforeEach(async () => { [getXpWeeklyLeaderboardMock, getResultMock, getFriendsUidsMock].forEach( (it) => it.mockClear(), ); vi.useFakeTimers(); vi.setSystemTime(1722606812000); await weeklyLeaderboardEnabled(true); getXpWeeklyLeaderboardMock.mockReturnValue({ getResults: getResultMock, } as any); getResultMock.mockResolvedValue(null); }); afterEach(() => { vi.useRealTimers(); }); it("should get", async () => { //GIVEN const lbConf = (await configuration).leaderboards.weeklyXp; const resultData: XpLeaderboardEntry[] = [ { totalXp: 100, rank: 1, timeTypedSeconds: 100, uid: "user1", name: "user1", discordId: "discordId", discordAvatar: "discordAvatar", lastActivityTimestamp: 1000, }, { totalXp: 75, rank: 2, timeTypedSeconds: 200, uid: "user2", name: "user2", discordId: "discordId2", discordAvatar: "discordAvatar2", lastActivityTimestamp: 2000, }, ]; getResultMock.mockResolvedValue({ count: 2, entries: resultData }); //WHEN const { body } = await mockApp .get("/leaderboards/xp/weekly") .query({}) .expect(200); //THEN expect(body).toEqual({ message: "Weekly xp leaderboard retrieved", data: { entries: resultData, count: 2, pageSize: 50, }, }); expect(getXpWeeklyLeaderboardMock).toHaveBeenCalledWith(lbConf, -1); expect(getResultMock).toHaveBeenCalledWith( 0, 50, lbConf, false, undefined, ); }); it("should get for last week", async () => { //GIVEN const lbConf = (await configuration).leaderboards.weeklyXp; //WHEN const { body } = await mockApp .get("/leaderboards/xp/weekly") .query({ weeksBefore: 1, }) .expect(200); //THEN expect(body).toEqual({ message: "Weekly xp leaderboard retrieved", data: { count: 0, entries: [], pageSize: 50, }, }); expect(getXpWeeklyLeaderboardMock).toHaveBeenCalledWith( lbConf, 1721606400000, ); }); it("should get with skip and limit", async () => { //GIVEN const lbConf = (await configuration).leaderboards.weeklyXp; const page = 2; const pageSize = 25; //WHEN const { body } = await mockApp .get("/leaderboards/xp/weekly") .query({ page, pageSize, }) .expect(200); //THEN expect(body).toEqual({ message: "Weekly xp leaderboard retrieved", data: { entries: [], count: 0, pageSize, }, }); expect(getXpWeeklyLeaderboardMock).toHaveBeenCalledWith(lbConf, -1); expect(getResultMock).toHaveBeenCalledWith( page, pageSize, lbConf, false, undefined, ); }); it("should get for friends", async () => { //GIVEN const lbConf = (await configuration).leaderboards.weeklyXp; await enableConnectionsFeature(true); const page = 2; const pageSize = 25; const friends = [ new ObjectId().toHexString(), new ObjectId().toHexString(), ]; getFriendsUidsMock.mockResolvedValue(friends); //WHEN await mockApp .get("/leaderboards/xp/weekly") .set("Authorization", `Bearer ${uid}`) .query({ page, pageSize, friendsOnly: true, }) .expect(200); //THEN expect(getXpWeeklyLeaderboardMock).toHaveBeenCalledWith(lbConf, -1); expect(getResultMock).toHaveBeenCalledWith( page, pageSize, lbConf, false, friends, ); }); it("fails if daily leaderboards are disabled", async () => { await weeklyLeaderboardEnabled(false); const { body } = await mockApp.get("/leaderboards/xp/weekly").expect(503); expect(body.message).toEqual( "Weekly XP leaderboards are not available at this time.", ); }); it("fails for weeksBefore not one", async () => { const { body } = await mockApp .get("/leaderboards/xp/weekly") .query({ weeksBefore: 2, }) .expect(422); expect(body).toEqual({ message: "Invalid query schema", validationErrors: ['"weeksBefore" Invalid literal value, expected 1'], }); }); it("fails for unknown query", async () => { const { body } = await mockApp .get("/leaderboards/xp/weekly") .query({ extra: "value", }) .expect(422); expect(body).toEqual({ message: "Invalid query schema", validationErrors: ["Unrecognized key(s) in object: 'extra'"], }); }); it("fails while leaderboard is missing", async () => { //GIVEN getXpWeeklyLeaderboardMock.mockReturnValue(null); //WHEN const { body } = await mockApp.get("/leaderboards/xp/weekly").expect(404); expect(body.message).toEqual("XP leaderboard for this week not found."); }); }); describe("get xp weekly leaderboard rank", () => { const getXpWeeklyLeaderboardMock = vi.spyOn(WeeklyXpLeaderboard, "get"); const getRankMock = vi.fn(); const getFriendsUidsMock = vi.spyOn(ConnectionsDal, "getFriendsUids"); beforeEach(async () => { [getXpWeeklyLeaderboardMock, getRankMock, getFriendsUidsMock].forEach( (it) => it.mockClear(), ); await weeklyLeaderboardEnabled(true); vi.useFakeTimers(); vi.setSystemTime(1722606812000); getXpWeeklyLeaderboardMock.mockReturnValue({ getRank: getRankMock, } as any); }); it("fails withouth authentication", async () => { await mockApp.get("/leaderboards/xp/weekly/rank").expect(401); }); it("should get", async () => { //GIVEN const lbConf = (await configuration).leaderboards.weeklyXp; const resultData: XpLeaderboardEntry = { totalXp: 100, rank: 1, timeTypedSeconds: 100, uid: "user1", name: "user1", discordId: "discordId", discordAvatar: "discordAvatar", lastActivityTimestamp: 1000, }; getRankMock.mockResolvedValue(resultData); //WHEN const { body } = await mockApp .get("/leaderboards/xp/weekly/rank") .set("Authorization", `Bearer ${uid}`) .expect(200); //THEN expect(body).toEqual({ message: "Weekly xp leaderboard rank retrieved", data: resultData, }); expect(getXpWeeklyLeaderboardMock).toHaveBeenCalledWith(lbConf, -1); expect(getRankMock).toHaveBeenCalledWith(uid, lbConf, undefined); }); it("should get for last week", async () => { //GIVEN const lbConf = (await configuration).leaderboards.weeklyXp; getRankMock.mockResolvedValue({}); //WHEN const { body } = await mockApp .get("/leaderboards/xp/weekly/rank") .query({ weeksBefore: 1 }) .set("Authorization", `Bearer ${uid}`) .expect(200); //THEN expect(body).toEqual({ message: "Weekly xp leaderboard rank retrieved", data: {}, }); expect(getXpWeeklyLeaderboardMock).toHaveBeenCalledWith( lbConf, 1721606400000, ); expect(getRankMock).toHaveBeenCalledWith(uid, lbConf, undefined); }); it("should get for friendsOnly", async () => { //GIVEN const lbConf = (await configuration).leaderboards.weeklyXp; await enableConnectionsFeature(true); getRankMock.mockResolvedValue({}); const friends = ["friendOne", "friendTwo"]; getFriendsUidsMock.mockResolvedValue(friends); //WHEN const { body } = await mockApp .get("/leaderboards/xp/weekly/rank") .query({ friendsOnly: true }) .set("Authorization", `Bearer ${uid}`) .expect(200); //THEN expect(body).toEqual({ message: "Weekly xp leaderboard rank retrieved", data: {}, }); expect(getXpWeeklyLeaderboardMock).toHaveBeenCalledWith(lbConf, -1); expect(getRankMock).toHaveBeenCalledWith(uid, lbConf, friends); }); it("fails if daily leaderboards are disabled", async () => { await weeklyLeaderboardEnabled(false); const { body } = await mockApp .get("/leaderboards/xp/weekly/rank") .set("Authorization", `Bearer ${uid}`) .expect(503); expect(body.message).toEqual( "Weekly XP leaderboards are not available at this time.", ); }); it("fails for weeksBefore not one", async () => { const { body } = await mockApp .get("/leaderboards/xp/weekly/rank") .set("Authorization", `Bearer ${uid}`) .query({ weeksBefore: 2, }) .expect(422); expect(body).toEqual({ message: "Invalid query schema", validationErrors: ['"weeksBefore" Invalid literal value, expected 1'], }); }); it("fails for unknown query", async () => { const { body } = await mockApp .get("/leaderboards/xp/weekly/rank") .set("Authorization", `Bearer ${uid}`) .query({ extra: "value", }) .expect(422); expect(body).toEqual({ message: "Invalid query schema", validationErrors: ["Unrecognized key(s) in object: 'extra'"], }); }); it("fails while leaderboard is missing", async () => { //GIVEN getXpWeeklyLeaderboardMock.mockReturnValue(null); //WHEN const { body } = await mockApp .get("/leaderboards/xp/weekly/rank") .set("Authorization", `Bearer ${uid}`) .expect(404); expect(body.message).toEqual("XP leaderboard for this week not found."); }); }); }); async function acceptApeKeys(enabled: boolean): Promise { const mockConfig = await configuration; mockConfig.apeKeys = { ...mockConfig.apeKeys, acceptKeys: enabled }; vi.spyOn(Configuration, "getCachedConfiguration").mockResolvedValue( mockConfig, ); } async function dailyLeaderboardEnabled(enabled: boolean): Promise { const mockConfig = await configuration; mockConfig.dailyLeaderboards = { ...mockConfig.dailyLeaderboards, enabled: enabled, }; vi.spyOn(Configuration, "getCachedConfiguration").mockResolvedValue( mockConfig, ); } async function weeklyLeaderboardEnabled(enabled: boolean): Promise { const mockConfig = await configuration; mockConfig.leaderboards.weeklyXp = { ...mockConfig.leaderboards.weeklyXp, enabled, }; vi.spyOn(Configuration, "getCachedConfiguration").mockResolvedValue( mockConfig, ); } async function enableConnectionsFeature(enabled: boolean): Promise { const mockConfig = await configuration; mockConfig.connections = { ...mockConfig.connections, enabled }; vi.spyOn(Configuration, "getCachedConfiguration").mockResolvedValue( mockConfig, ); }