diff --git a/README.md b/README.md index 4ee325b..c3fbe2e 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,7 @@ Click the function names to open their complete docs on the docs site. - [`getUserRecentlyPlayedGames()`](https://api-docs.retroachievements.org/v1/get-user-recently-played-games.html) - Get a list of games a user has recently played. - [`getUserSummary()`](https://api-docs.retroachievements.org/v1/get-user-summary.html) - Get a user's profile metadata. - [`getUserCompletedGames()`](https://api-docs.retroachievements.org/v1/get-user-completed-games.html) - Deprecated function. Get hardcore and softcore completion metadata about games a user has played. +- [`getUserWantToPlayList()`](https://api-docs.retroachievements.org/v1/get-user-want-to-play-list.html) - Get a user's "Want to Play Games" list. ### Game diff --git a/src/game/getGameExtended.test.ts b/src/game/getGameExtended.test.ts index 590b6ff..406d400 100644 --- a/src/game/getGameExtended.test.ts +++ b/src/game/getGameExtended.test.ts @@ -75,7 +75,10 @@ describe("Function: getGameExtended", () => { ); // ACT - const response = await getGameExtended(authorization, { gameId: 14_402 }); + const response = await getGameExtended(authorization, { + gameId: 14_402, + isRequestingUnofficialAchievements: true, + }); // ASSERT expect(response).toEqual({ diff --git a/src/game/getGameHashes.test.ts b/src/game/getGameHashes.test.ts index db64350..44d9189 100644 --- a/src/game/getGameHashes.test.ts +++ b/src/game/getGameHashes.test.ts @@ -10,7 +10,7 @@ import type { GetGameHashesResponse } from "./models"; const server = setupServer(); -describe("Function: getGameExtended", () => { +describe("Function: getGameHashes", () => { // MSW Setup beforeAll(() => server.listen()); afterEach(() => server.resetHandlers()); @@ -21,7 +21,7 @@ describe("Function: getGameExtended", () => { expect(getGameHashes).toBeDefined(); }); - it("given a game ID, retrieves extended metadata about the game", async () => { + it("given a game ID, retrieves a list of linked hashes", async () => { // ARRANGE const authorization = buildAuthorization({ username: "mockUserName", diff --git a/src/game/getGameHashes.ts b/src/game/getGameHashes.ts index 7e5e650..05cee65 100644 --- a/src/game/getGameHashes.ts +++ b/src/game/getGameHashes.ts @@ -30,18 +30,18 @@ import type { GameHashes, GetGameHashesResponse } from "./models"; * @returns An object containing a list of game hashes. * ```json * { - * "Results": [ + * "results": [ * { - * "MD5": "1b1d9ac862c387367e904036114c4825", - * "Name": "Sonic The Hedgehog (USA, Europe) (Ru) (NewGame).md", - * "Labels": ["nointro", "rapatches"], - * "PatchUrl": "https://github.com/RetroAchievements/RAPatches/raw/main/MD/Translation/Russian/1-Sonic1-Russian.zip" + * "md5": "1b1d9ac862c387367e904036114c4825", + * "name": "Sonic The Hedgehog (USA, Europe) (Ru) (NewGame).md", + * "labels": ["nointro", "rapatches"], + * "patchUrl": "https://github.com/RetroAchievements/RAPatches/raw/main/MD/Translation/Russian/1-Sonic1-Russian.zip" * }, * { - * "MD5": "1bc674be034e43c96b86487ac69d9293", - * "Name": "Sonic The Hedgehog (USA, Europe).md", - * "Labels": ["nointro"], - * "PatchUrl": null + * "md5": "1bc674be034e43c96b86487ac69d9293", + * "name": "Sonic The Hedgehog (USA, Europe).md", + * "labels": ["nointro"], + * "patchUrl": null * } * ] * } diff --git a/src/user/getUserWantToPlayList.test.ts b/src/user/getUserWantToPlayList.test.ts new file mode 100644 index 0000000..a30a9a5 --- /dev/null +++ b/src/user/getUserWantToPlayList.test.ts @@ -0,0 +1,75 @@ +/* eslint-disable sonarjs/no-duplicate-string */ + +import { http, HttpResponse } from "msw"; +import { setupServer } from "msw/node"; + +import { apiBaseUrl } from "../utils/internal"; +import { buildAuthorization } from "../utils/public"; +import { getUserWantToPlayList } from "./getUserWantToPlayList"; +import type { GetUserWantToPlayListResponse } from "./models"; + +const server = setupServer(); + +describe("Function: getUserWantToPlayList", () => { + // MSW Setup + beforeAll(() => server.listen()); + afterEach(() => server.resetHandlers()); + afterAll(() => server.close()); + + it("is defined #sanity", () => { + // ASSERT + expect(getUserWantToPlayList).toBeDefined(); + }); + + it('given a username, retrieves that users "Want To Play Games"', async () => { + // ARRANGE + const authorization = buildAuthorization({ + username: "mockUserName", + webApiKey: "mockWebApiKey", + }); + + const mockResponse: GetUserWantToPlayListResponse = { + Count: 100, + Total: 1287, + Results: [ + { + ID: 20_246, + Title: "~Hack~ Knuckles the Echidna in Sonic the Hedgehog", + ImageIcon: "/Images/074560.png", + ConsoleID: 1, + ConsoleName: "Genesis/Mega Drive", + PointsTotal: 1500, + AchievementsPublished: 50, + }, + ], + }; + + server.use( + http.get(`${apiBaseUrl}/API_GetUserWantToPlayList.php`, () => + HttpResponse.json(mockResponse) + ) + ); + + // ACT + const response = await getUserWantToPlayList(authorization, { + username: "xelnia", + }); + + // ASSERT + expect(response).toEqual({ + count: 100, + total: 1287, + results: [ + { + id: 20_246, + title: "~Hack~ Knuckles the Echidna in Sonic the Hedgehog", + imageIcon: "/Images/074560.png", + consoleId: 1, + consoleName: "Genesis/Mega Drive", + pointsTotal: 1500, + achievementsPublished: 50, + }, + ], + }); + }); +}); diff --git a/src/user/getUserWantToPlayList.ts b/src/user/getUserWantToPlayList.ts new file mode 100644 index 0000000..b451be5 --- /dev/null +++ b/src/user/getUserWantToPlayList.ts @@ -0,0 +1,76 @@ +import { + apiBaseUrl, + buildRequestUrl, + call, + serializeProperties, +} from "../utils/internal"; +import type { AuthObject } from "../utils/public"; +import type { + GetUserWantToPlayListResponse, + UserWantToPlayList, +} from "./models"; + +/** + * A call to this function will retrieve a user's "Want to Play Games" list. + * + * @param authorization An object containing your username and webApiKey. + * This can be constructed with `buildAuthorization()`. + * + * @param payload.username The user for which to retrieve the + * want to play games list for. + * + * @param payload.offset Defaults to 0. The number of entries to skip. + * + * @param payload.count Defaults to 100, has a max of 500. + * + * @example + * ``` + * const wantToPlayList = await getUserWantToPlayList( + * authorization, + * { username: "wv_pinball" } + * ); + * ``` + * + * @returns An object containing a user's list of "Want to Play Games". + * ```json + * { + * "count": 100, + * "total": 1287, + * "results": [ + * { + * "id": 20246, + * "title": "~Hack~ Knuckles the Echidna in Sonic the Hedgehog", + * "imageIcon": "/Images/074560.png", + * "consoleID": 1, + * "consoleName": "Genesis/Mega Drive", + * "pointsTotal": 1500, + * "achievementsPublished": 50 + * } + * ] + * } + * ``` + */ +export const getUserWantToPlayList = async ( + authorization: AuthObject, + payload: { username: string; offset?: number; count?: number } +): Promise => { + const queryParams: Record = {}; + queryParams.u = payload.username; + if (payload?.offset) { + queryParams.o = payload.offset; + } + if (payload?.count) { + queryParams.c = payload.count; + } + + const url = buildRequestUrl( + apiBaseUrl, + "/API_GetUserWantToPlayList.php", + authorization, + queryParams + ); + + const rawResponse = await call({ url }); + + return serializeProperties(rawResponse); +}; diff --git a/src/user/index.ts b/src/user/index.ts index e6c1e38..e3e317c 100644 --- a/src/user/index.ts +++ b/src/user/index.ts @@ -12,4 +12,5 @@ export * from "./getUserProgress"; export * from "./getUserRecentAchievements"; export * from "./getUserRecentlyPlayedGames"; export * from "./getUserSummary"; +export * from "./getUserWantToPlayList"; export * from "./models"; diff --git a/src/user/models/get-user-want-to-play-list-response.model.ts b/src/user/models/get-user-want-to-play-list-response.model.ts new file mode 100644 index 0000000..5b72b7d --- /dev/null +++ b/src/user/models/get-user-want-to-play-list-response.model.ts @@ -0,0 +1,13 @@ +export interface GetUserWantToPlayListResponse { + Count: number; + Total: number; + Results: Array<{ + ID: number; + Title: string; + ImageIcon: string; + ConsoleID: number; + ConsoleName: string; + PointsTotal: number; + AchievementsPublished: number; + }>; +} diff --git a/src/user/models/index.ts b/src/user/models/index.ts index b0f5ab6..91c2d99 100644 --- a/src/user/models/index.ts +++ b/src/user/models/index.ts @@ -13,6 +13,7 @@ export * from "./get-user-progress-response.model"; export * from "./get-user-recent-achievements-response.model"; export * from "./get-user-recently-played-games-response.model"; export * from "./get-user-summary-response.model"; +export * from "./get-user-want-to-play-list-response.model"; export * from "./user-awards.model"; export * from "./user-claims.model"; export * from "./user-claims-response.model"; @@ -26,3 +27,4 @@ export * from "./user-progress.model"; export * from "./user-recent-achievement.model"; export * from "./user-recently-played-games.model"; export * from "./user-summary.model"; +export * from "./user-want-to-play-list.model"; diff --git a/src/user/models/user-want-to-play-list.model.ts b/src/user/models/user-want-to-play-list.model.ts new file mode 100644 index 0000000..1ffdc11 --- /dev/null +++ b/src/user/models/user-want-to-play-list.model.ts @@ -0,0 +1,13 @@ +export interface UserWantToPlayList { + count: number; + total: number; + results: Array<{ + id: number; + title: string; + imageIcon: string; + consoleId: number; + consoleName: string; + pointsTotal: number; + achievementsPublished: number; + }>; +}