Skip to content

Commit 422449c

Browse files
committed
Created tests in api/unclaimedItems/route.test.ts
Created documentation and GET for api/unclaimedItems/route.ts Created authMockUtil and dbMockUtils tools for easier verification and db testing No idea what I did to authMock but it is working properly
1 parent 88b6f90 commit 422449c

File tree

6 files changed

+157
-1
lines changed

6 files changed

+157
-1
lines changed
+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { testApiHandler } from "next-test-api-route-handler";
2+
import * as appHandler from "./route";
3+
import { expect, test } from "@jest/globals";
4+
import { authMock } from "@/test/authMock";
5+
import { validateSession, invalidateSession } from "@/test/util/authMockUtils";
6+
import { manyUnclaimedItems } from "@/test/util/dbMockUtils";
7+
import { dbMock } from "@/test/dbMock";
8+
import { UnclaimedItem } from "@prisma/client";
9+
10+
test("Should return 401 for invalid session", async () => {
11+
await testApiHandler({
12+
appHandler,
13+
async test({ fetch }) {
14+
invalidateSession();
15+
16+
const res = await fetch({ method: "GET" });
17+
await expect(res.status).toBe(401);
18+
const json = await res.json();
19+
await expect(json).toEqual({ message: "Session required" });
20+
}
21+
})
22+
});
23+
24+
test("Should return 200 for valid session", async () => {
25+
await testApiHandler({
26+
appHandler,
27+
async test({ fetch }) {
28+
validateSession();
29+
30+
const res = await fetch({ method: "GET" });
31+
await expect(res.status).toBe(200);
32+
}
33+
})
34+
});
35+
36+
test("Should give correct database queries", async () => {
37+
await testApiHandler({
38+
appHandler,
39+
async test({ fetch }) {
40+
// Create mock data
41+
dbMock.unclaimedItem.create({ data: { id: 1, name: "Test Item 1", quantity: 1, expirationDate: new Date() } });
42+
const items: UnclaimedItem[] = await manyUnclaimedItems(3);
43+
// Convert items expirationDate to ISO-8601 string
44+
const expectedRet = items.map(item => {
45+
return { ...item, expirationDate: item.expirationDate?.toISOString() || "" }
46+
});
47+
48+
validateSession();
49+
50+
const res = await fetch({ method: "GET" });
51+
await expect(res.status).toBe(200);
52+
53+
// Check that the database was queried
54+
await expect(dbMock.unclaimedItem.findMany).toHaveBeenCalledTimes(1);
55+
56+
// Check that the response json was written correctly
57+
const json = await res.json();
58+
await expect(json["unclaimedItems"]).toEqual(expectedRet);
59+
}
60+
})
61+
});

src/app/api/unclaimedItems/route.ts

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { NextRequest } from 'next/server';
2+
import { auth } from '@/auth';
3+
import { internalError, authenticationError, successResponse } from '@/util/responses';
4+
import { db } from '@/db';
5+
6+
/**
7+
* Handles GET requests to retrieve unclaimed items from the unclaimedItem database.
8+
*
9+
* @returns {NextResponse} On success, returns a status of 200 and a JSON object containing an array of unclaimed items.
10+
* @returns {NextResponse} On authentication error, returns a status of 401 and a JSON object containing an error message.
11+
* @returns {NextResponse} On error, returns a status of 500 and a JSON object containing an error message.
12+
*
13+
* @example
14+
* // Example response:
15+
* {
16+
* "unclaimedItems": [
17+
* {
18+
* "id": 1,
19+
* "name": "Banana",
20+
* "quantity": 10,
21+
* "expirationDate": "2025-01-22T14:45:43.241Z"
22+
* },
23+
* {
24+
* "id": 2,
25+
* "name": "Apple",
26+
* "quantity": 100,
27+
* "expirationDate": "2025-01-22T14:45:43.243Z"
28+
* }
29+
* ]
30+
* }
31+
*/
32+
export async function GET() {
33+
try {
34+
const session = await auth();
35+
if (!session) return authenticationError('Session required');
36+
37+
// Get all unclaimed items
38+
const unclaimedItems = await db.unclaimedItem.findMany();
39+
40+
return successResponse({ unclaimedItems });
41+
} catch (err: any) {
42+
console.error(err?.message);
43+
return internalError();
44+
}
45+
}

src/test/authMock.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@ beforeEach(() => {
1313
mockReset(authMock);
1414
});
1515

16-
export const authMock = auth as unknown as jest.Mock<() => Session | null>;
16+
export const authMock = auth as unknown as jest.Mock<() => Session | null>;

src/test/util/authMockUtils.ts

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { authMock } from "@/test/authMock";
2+
3+
// Helper util methods for testing
4+
5+
/**
6+
* Helper method for invalidating a session
7+
*/
8+
export async function invalidateSession() {
9+
authMock.mockReturnValueOnce(null);
10+
}
11+
12+
/**
13+
* Helper method for validating a session
14+
* @param user Optional, default is { id: "1234", type: "ADMIN" }
15+
* @param expires Optional, default is ""
16+
*/
17+
export async function validateSession(user: any = { id: "1234", type: "ADMIN" }, expires: string = "") {
18+
authMock.mockReturnValueOnce({
19+
user: {
20+
id: user.id,
21+
type: user.type,
22+
},
23+
expires: expires,
24+
});
25+
}

src/test/util/dbMockUtils.ts

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { dbMock } from "@/test/dbMock";
2+
import { UnclaimedItem } from "@prisma/client";
3+
4+
5+
// Helper util methods for testing
6+
7+
8+
/**
9+
* Helper method for creating unclaimed items
10+
* Defines the db.unclaimedItem.findMany mock
11+
* @param num Number of items to create
12+
* @returns Array of UnclaimedItems returned by db.unclaimedItem.findMany mock
13+
*/
14+
export async function manyUnclaimedItems(num: number): Promise<UnclaimedItem[]> {
15+
const items: UnclaimedItem[] = [];
16+
for (let i = 0; i < num; i++) {
17+
items.push({id: i, name: `Test Item ${i}`, quantity: i, expirationDate: new Date()});
18+
}
19+
dbMock.unclaimedItem.findMany.mockResolvedValue(items);
20+
return items;
21+
}

src/util/responses.ts

+4
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,7 @@ export function internalError() {
2727
export function ok() {
2828
return NextResponse.json({ message: "OK" }, { status: 200 });
2929
}
30+
31+
export function successResponse(data: any) {
32+
return NextResponse.json(data, { status: 200 });
33+
}

0 commit comments

Comments
 (0)