diff --git a/src/app/api/v1/stock-purchases/list/route.test.ts b/src/app/api/v1/stock-purchases/list/route.test.ts index d4382b5..e4aaba2 100644 --- a/src/app/api/v1/stock-purchases/list/route.test.ts +++ b/src/app/api/v1/stock-purchases/list/route.test.ts @@ -93,4 +93,38 @@ describe("/api/v1/stock-purchases/list", () => { const body = await res.json(); expect(body.error).toBe("PB is down"); }); + + it("returns 401 when the request is not authenticated", async () => { + // No bearer header — assertAgentAuth throws with status: 401. + const req = new NextRequest("http://localhost/api/v1/stock-purchases/list"); + const res = await GET(req); + expect(res.status).toBe(401); + expect(listStockPurchases).not.toHaveBeenCalled(); + }); + + it("clamps page/perPage and falls back to defaults on malformed input", async () => { + listStockPurchases.mockResolvedValue({ + items: [], + totalItems: 0, + page: 1, + perPage: 50, + totalPages: 0, + }); + + const cases: Array<[string, { status: ""; page: number; perPage: number }]> = [ + ["?page=0", { status: "", page: 1, perPage: 50 }], + ["?page=abc", { status: "", page: 1, perPage: 50 }], + ["?perPage=0", { status: "", page: 1, perPage: 50 }], + ["?perPage=abc", { status: "", page: 1, perPage: 50 }], + ["?perPage=999", { status: "", page: 1, perPage: 200 }], + ]; + + for (const [qs, expected] of cases) { + listStockPurchases.mockClear(); + await GET( + authedRequest(`http://localhost/api/v1/stock-purchases/list${qs}`), + ); + expect(listStockPurchases).toHaveBeenCalledWith(expect.anything(), expected); + } + }); }); diff --git a/src/app/api/v1/stock-purchases/list/route.ts b/src/app/api/v1/stock-purchases/list/route.ts index c20b6da..0818caa 100644 --- a/src/app/api/v1/stock-purchases/list/route.ts +++ b/src/app/api/v1/stock-purchases/list/route.ts @@ -39,10 +39,16 @@ export async function GET(req: NextRequest) { } const status = rawStatus as StockPurchaseStatus | ""; - const page = Math.max(1, Number(req.nextUrl.searchParams.get("page") || "1")); + const page = Math.max( + 1, + Number(req.nextUrl.searchParams.get("page") || "1") || 1, + ); const perPage = Math.min( 200, - Math.max(1, Number(req.nextUrl.searchParams.get("perPage") || "50")), + Math.max( + 1, + Number(req.nextUrl.searchParams.get("perPage") || "50") || 50, + ), ); const pb = await getAdminPocketBase(); @@ -51,6 +57,7 @@ export async function GET(req: NextRequest) { } catch (error) { const message = error instanceof Error ? error.message : "Failed to fetch stock-purchases"; - return NextResponse.json({ error: message }, { status: 500 }); + const status = (error as Error & { status?: number }).status || 500; + return NextResponse.json({ error: message }, { status }); } }