Skip to content

Commit 29b6e97

Browse files
committed
add unit testing around external lists
1 parent 5d3d7f3 commit 29b6e97

File tree

2 files changed

+130
-3
lines changed

2 files changed

+130
-3
lines changed

tests/unit/membership.test.ts

Lines changed: 104 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
import { afterAll, expect, test, vi } from "vitest";
22
import init from "../../src/api/index.js";
33
import { EventGetResponse } from "../../src/api/routes/events.js";
4-
import { describe } from "node:test";
4+
import { afterEach, describe } from "node:test";
55
import { setPaidMembershipInTable } from "../../src/api/functions/membership.js";
6+
import { DynamoDBClient, QueryCommand } from "@aws-sdk/client-dynamodb";
7+
import { genericConfig } from "../../src/common/config.js";
8+
import { marshall } from "@aws-sdk/util-dynamodb";
9+
import { mockClient } from "aws-sdk-client-mock";
610

711
const app = await init();
12+
const ddbMock = mockClient(DynamoDBClient);
13+
814
vi.mock("../../src/api/functions/entraId.js", () => {
915
return {
1016
...vi.importActual("../../src/api/functions/entraId.js"),
@@ -46,22 +52,117 @@ describe("Test membership routes", async () => {
4652
});
4753

4854
test("Entra-only members are added to Dynamo", async () => {
49-
const response = await app.inject({
55+
let response = await app.inject({
5056
method: "GET",
5157
url: "/api/v1/membership/eadon2",
5258
});
5359

5460
expect(response.statusCode).toBe(200);
55-
const responseDataJson = (await response.json()) as EventGetResponse;
61+
let responseDataJson = (await response.json()) as EventGetResponse;
5662
expect(response.headers).toHaveProperty("x-acm-data-source");
5763
expect(response.headers["x-acm-data-source"]).toEqual("aad");
5864
expect(responseDataJson).toEqual({ netId: "eadon2", isPaidMember: true });
5965
expect(spySetPaidMembership).toHaveBeenCalledWith(
6066
"eadon2",
6167
expect.any(Object),
6268
);
69+
response = await app.inject({
70+
method: "GET",
71+
url: "/api/v1/membership/eadon2",
72+
});
73+
expect(response.statusCode).toBe(200);
74+
responseDataJson = (await response.json()) as EventGetResponse;
75+
expect(response.headers).toHaveProperty("x-acm-data-source");
76+
expect(response.headers["x-acm-data-source"]).toEqual("cache");
77+
expect(responseDataJson).toEqual({ netId: "eadon2", isPaidMember: true });
6378
});
79+
test("External list members are correctly found", async () => {
80+
ddbMock.on(QueryCommand).callsFake((command) => {
81+
if (command.TableName === genericConfig.ExternalMembershipTableName) {
82+
const requestedEmail = command.ExpressionAttributeValues[":pk"].S;
83+
const mockMembershipData = {
84+
eadon2_built: { netid_list: "eadon2_built" },
85+
yourm4_wcs: { netid_list: "yourm4_wcs" },
86+
};
6487

88+
return Promise.resolve({
89+
Items: mockMembershipData[requestedEmail]
90+
? [marshall(mockMembershipData[requestedEmail])]
91+
: [],
92+
});
93+
}
94+
return Promise.reject(new Error("Table not mocked"));
95+
});
96+
let response = await app.inject({
97+
method: "GET",
98+
url: "/api/v1/membership/eadon2?list=built",
99+
});
100+
101+
expect(response.statusCode).toBe(200);
102+
let responseDataJson = (await response.json()) as EventGetResponse;
103+
expect(response.headers).toHaveProperty("x-acm-data-source");
104+
expect(response.headers["x-acm-data-source"]).toEqual("dynamo");
105+
expect(responseDataJson).toEqual({
106+
netId: "eadon2",
107+
list: "built",
108+
isPaidMember: true,
109+
});
110+
response = await app.inject({
111+
method: "GET",
112+
url: "/api/v1/membership/eadon2?list=wcs",
113+
});
114+
expect(response.statusCode).toBe(200);
115+
responseDataJson = (await response.json()) as EventGetResponse;
116+
expect(response.headers).toHaveProperty("x-acm-data-source");
117+
expect(response.headers["x-acm-data-source"]).toEqual("dynamo");
118+
expect(responseDataJson).toEqual({
119+
netId: "eadon2",
120+
list: "wcs",
121+
isPaidMember: false,
122+
});
123+
response = await app.inject({
124+
method: "GET",
125+
url: "/api/v1/membership/yourm4?list=wcs",
126+
});
127+
expect(response.statusCode).toBe(200);
128+
responseDataJson = (await response.json()) as EventGetResponse;
129+
expect(response.headers).toHaveProperty("x-acm-data-source");
130+
expect(response.headers["x-acm-data-source"]).toEqual("dynamo");
131+
expect(responseDataJson).toEqual({
132+
netId: "yourm4",
133+
list: "wcs",
134+
isPaidMember: true,
135+
});
136+
response = await app.inject({
137+
method: "GET",
138+
url: "/api/v1/membership/eadon2?list=wcs",
139+
});
140+
expect(response.statusCode).toBe(200);
141+
responseDataJson = (await response.json()) as EventGetResponse;
142+
expect(response.headers).toHaveProperty("x-acm-data-source");
143+
expect(response.headers["x-acm-data-source"]).toEqual("cache");
144+
expect(responseDataJson).toEqual({
145+
netId: "eadon2",
146+
list: "wcs",
147+
isPaidMember: false,
148+
});
149+
response = await app.inject({
150+
method: "GET",
151+
url: "/api/v1/membership/eadon2?list=built",
152+
});
153+
expect(response.statusCode).toBe(200);
154+
responseDataJson = (await response.json()) as EventGetResponse;
155+
expect(response.headers).toHaveProperty("x-acm-data-source");
156+
expect(response.headers["x-acm-data-source"]).toEqual("cache");
157+
expect(responseDataJson).toEqual({
158+
netId: "eadon2",
159+
list: "built",
160+
isPaidMember: true,
161+
});
162+
});
163+
afterEach(async () => {
164+
ddbMock.reset();
165+
});
65166
afterAll(async () => {
66167
await app.close();
67168
});

tests/unit/vitest.setup.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import { vi } from "vitest";
22
import { allAppRoles, AppRoles } from "../../src/common/roles.js";
3+
import { DynamoDBClient, QueryCommand } from "@aws-sdk/client-dynamodb";
4+
import { mockClient } from "aws-sdk-client-mock";
5+
import { marshall } from "@aws-sdk/util-dynamodb";
6+
import { genericConfig } from "../../src/common/config.js";
7+
8+
const ddbMock = mockClient(DynamoDBClient);
39

410
vi.mock(
511
import("../../src/api/functions/rateLimit.js"),
@@ -74,3 +80,23 @@ vi.mock(
7480
};
7581
},
7682
);
83+
84+
ddbMock.on(QueryCommand).callsFake((command) => {
85+
if (command.input.TableName === genericConfig.MembershipTableName) {
86+
const requestedEmail = command.input.ExpressionAttributeValues[":pk"].S;
87+
const mockMembershipData = {
88+
89+
90+
inserted_at: "2025-03-08T20:46:36.517561",
91+
inserted_by: "core-api-provisioned",
92+
},
93+
};
94+
95+
return Promise.resolve({
96+
Items: mockMembershipData[requestedEmail]
97+
? [marshall(mockMembershipData[requestedEmail])]
98+
: [],
99+
});
100+
}
101+
return Promise.reject(new Error("Table not mocked"));
102+
});

0 commit comments

Comments
 (0)