Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ Click the function names to open their complete docs on the docs site.
- [`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.
- [`getUsersIFollow()`](https://api-docs.retroachievements.org/v1/get-users-i-follow.html) - Get the caller's "Following" users list.
- [`getUserSetRequests()`](https://api-docs.retroachievements.org/v1/get-user-set-requests.html) - Get a given user's set requests, maximum total requests, and points until next request.

### Game

Expand Down
149 changes: 149 additions & 0 deletions src/user/getUserSetRequests.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import { http, HttpResponse } from "msw";
import { setupServer } from "msw/node";

import { apiBaseUrl } from "../utils/internal";
import { buildAuthorization } from "../utils/public";
import { getUserSetRequests } from "./getUserSetRequests";
import type { GetUserSetRequestsResponse, UserSetRequests } from "./models";
import { RequestListType } from "./models";

const server = setupServer();

describe("Function: getUserSetRequests", () => {
// MSW Setup
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

it("is defined #sanity", () => {
// ASSERT
expect(getUserSetRequests).toBeDefined();
});

it("using defaults, retrieves the list of set requests of the given user", async () => {
// ARRANGE
const authorization = buildAuthorization({
username: "mockUserName",
webApiKey: "mockWebApiKey",
});

const mockResponse = mockGetUserSetRequestsResponse;

server.use(
http.get(`${apiBaseUrl}/API_GetUserSetRequests.php`, (info) => {
const url = new URL(info.request.url);
expect(url.searchParams.get("u")).toEqual(mockOtherUsername);
expect(url.searchParams.has("t")).toBeFalsy();
return HttpResponse.json(mockResponse);
})
);

// ACT
const response = await getUserSetRequests(authorization, {
username: mockOtherUsername,
});
expect(response).toEqual(mockUserSetRequestsValue);
});

it.each([
{ requestListType: RequestListType.ActiveRequests },
{ requestListType: RequestListType.AllRequests },
])(
"calls the 'User Set Requests' endpoint with a given request list type ($requestListType)",
async ({ requestListType: expectedRequestListType }) => {
// ARRANGE
const authorization = buildAuthorization({
username: "mockUserName",
webApiKey: "mockWebApiKey",
});

server.use(
http.get(`${apiBaseUrl}/API_GetUserSetRequests.php`, (info) => {
const url = new URL(info.request.url);
expect(url.searchParams.get("u")).toEqual(mockOtherUsername);
expect(url.searchParams.get("t")).toEqual(
String(expectedRequestListType)
);
return HttpResponse.json(mockGetUserSetRequestsResponse);
})
);

// ACT
await getUserSetRequests(authorization, {
username: mockOtherUsername,
requestListType: expectedRequestListType,
});
}
);

it.each([
{ status: 503, statusText: "The API is currently down" },
{ status: 422, statusText: "HTTP Error: Status 422 Unprocessable Entity" },
])(
"given the API returns a $status, throws an error",
async ({ status, statusText }) => {
// ARRANGE
const authorization = buildAuthorization({
username: "mockUserName",
webApiKey: "mockWebApiKey",
});

const mockResponse = `<html><body>${statusText}</body></html>`;

server.use(
http.get(`${apiBaseUrl}/API_GetUserSetRequests.php`, () =>
HttpResponse.json(mockResponse, { status, statusText })
)
);

// ASSERT
await expect(
getUserSetRequests(authorization, { username: mockOtherUsername })
).rejects.toThrow();
}
);
});

const mockOtherUsername = "otherMockUser";

const mockGetUserSetRequestsResponse: GetUserSetRequestsResponse = {
RequestedSets: [
{
GameID: 8149,
Title: "Example Set 1",
ConsoleID: 0,
ConsoleName: "Example Console",
ImageIcon: "/Images/000001.png",
},
{
GameID: 9001,
Title: "Example Set 2",
ConsoleID: 2,
ConsoleName: "Example Console 2",
ImageIcon: "/Images/000002.png",
},
],
TotalRequests: 5,
PointsForNext: 5000,
};

const mockUserSetRequestsValue: UserSetRequests = {
requestedSets: [
{
gameId: 8149,
title: "Example Set 1",
consoleId: 0,
consoleName: "Example Console",
imageIcon: "/Images/000001.png",
},
{
gameId: 9001,
title: "Example Set 2",
consoleId: 2,
consoleName: "Example Console 2",
imageIcon: "/Images/000002.png",
},
],
totalRequests: 5,
pointsForNext: 5000,
};
92 changes: 92 additions & 0 deletions src/user/getUserSetRequests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import {
apiBaseUrl,
buildRequestUrl,
call,
serializeProperties,
} from "../utils/internal";
import type { AuthObject } from "../utils/public";
import type {
GetUserSetRequestsResponse,
RequestListType,
UserSetRequests,
} from "./models";

/**
* A call to this function will retrieve a given user's set requests.
*
* @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 set requests
* for.
*
* @param payload.requestListType An optional parameter to filter set requests
* by their current status. If omittted, the API will return only active
Comment thread
wescopeland marked this conversation as resolved.
Outdated
* requests.
*
* @example
* ```
* const userSetRequests = await getUserSetRequests(authorization, {
* username: "ExampleUser"
* });
* ```
*
* @returns An object containing a list of requested sets that the
* given user made.
* ```json
* {
* "requestedSets": [
* {
* "gameId": 8149,
* "title": "Example Set 1",
* "consoleId": 0,
* "consoleName": "Example Console",
* "imageIcon": "/Images/000001.png"
* },
* {
* "gameId": 9001,
* "title": "Example Set 2",
* "consoleId": 2,
* "consoleName": "Example Console 2",
* "imageIcon": "/Images/000002.png"
* }
* ],
* "totalRequests": 5,
* "pointsForNext": 5000
* }
* ```
*
* @throws If the API was given invalid parameters (422) or if the
* API is currently down (503).
*/
export const getUserSetRequests = async (
authorization: AuthObject,
payload: { username: string; requestListType?: RequestListType }
): Promise<UserSetRequests> => {
const queryParams: Record<string, number | string> = {};
queryParams.u = payload.username;
if (
payload.requestListType !== null &&
payload.requestListType !== undefined
) {
queryParams.t = payload.requestListType;
}

const url = buildRequestUrl(
apiBaseUrl,
"/API_GetUserSetRequests.php",
authorization,
queryParams
);

const rawResponse = await call<GetUserSetRequestsResponse>({ url });

return serializeProperties(rawResponse, {
shouldCastToNumbers: [
"GameID",
"ConsoleID",
"TotalRequests",
"PointsForNext",
],
});
};
1 change: 1 addition & 0 deletions src/user/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export * from "./getUserProfile";
export * from "./getUserProgress";
export * from "./getUserRecentAchievements";
export * from "./getUserRecentlyPlayedGames";
export * from "./getUserSetRequests";
export * from "./getUsersIFollow";
export * from "./getUserSummary";
export * from "./getUserWantToPlayList";
Expand Down
11 changes: 11 additions & 0 deletions src/user/models/get-user-set-requests-response.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export interface GetUserSetRequestsResponse {
RequestedSets: Array<{
GameID: number | string;
Title: string;
ConsoleID: number | string;
ConsoleName: string;
ImageIcon: string;
}>;
TotalRequests: number;
PointsForNext: number;
}
3 changes: 3 additions & 0 deletions src/user/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ export * from "./get-user-profile-response.model";
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-set-requests-response.model";
export * from "./get-user-summary-response.model";
export * from "./get-user-want-to-play-list-response.model";
export * from "./get-users-i-follow-response.model";
export * from "./request-list-type.enum";
export * from "./user-awards.model";
export * from "./user-claims.model";
export * from "./user-claims-response.model";
Expand All @@ -27,6 +29,7 @@ export * from "./user-profile.model";
export * from "./user-progress.model";
export * from "./user-recent-achievement.model";
export * from "./user-recently-played-games.model";
export * from "./user-set-requests.model";
export * from "./user-summary.model";
export * from "./user-want-to-play-list.model";
export * from "./users-i-follow.model";
4 changes: 4 additions & 0 deletions src/user/models/request-list-type.enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export enum RequestListType {
ActiveRequests = 0,
AllRequests = 1,
}
11 changes: 11 additions & 0 deletions src/user/models/user-set-requests.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export interface UserSetRequests {
requestedSets: Array<{
gameId: number;
title: string;
consoleId: number;
consoleName: string;
imageIcon: string;
}>;
totalRequests: number;
pointsForNext: number;
}