import { describe, it, expect, beforeAll, afterAll } from "vitest"; import Fastify from "fastify"; import cookie from "@fastify/cookie"; import rateLimit from "@fastify/rate-limit"; import jwt from "jsonwebtoken"; import prisma from "../config/database"; import { config } from "../config/env"; import { securityHeaders } from "../middleware/security"; import warehouseRoutes from "../routes/admin/warehouse"; /** * Pinning tests for the verified-adjacent audit finding: GET /items ignores * the client `sort` param (the WarehouseItems page sends one — default * item_number) and hardcodes `orderBy: { name: "asc" }` with no `{ id }` * tiebreak. */ const N = "wh_itemsort_"; let app: ReturnType; let adminToken: string; // Names sort A→B, item numbers sort the OPPOSITE way, so honoring the sort // param produces a different first row than the hardcoded name ordering. let itemAId: number; // name "...a_name", item_number "...Z2" let itemBId: number; // name "...b_name", item_number "...A1" async function cleanup() { await prisma.sklad_items.deleteMany({ where: { name: { contains: N } } }); } beforeAll(async () => { await cleanup(); app = Fastify({ logger: false }); await app.register(cookie); await app.register(rateLimit, { max: 1000, timeWindow: "1 minute" }); app.addHook("onRequest", securityHeaders); await app.register(warehouseRoutes, { prefix: "/api/admin/warehouse" }); const admin = await prisma.users.findFirst({ where: { roles: { name: "admin" } }, }); if (!admin) throw new Error("Test setup: admin user not found"); adminToken = jwt.sign( { sub: admin.id, username: admin.username, role: "admin" }, config.jwt.secret, { expiresIn: "15m" }, ); const itemA = await prisma.sklad_items.create({ data: { name: `${N}a_name`, item_number: `${N}Z2`, unit: "ks" }, }); itemAId = itemA.id; const itemB = await prisma.sklad_items.create({ data: { name: `${N}b_name`, item_number: `${N}A1`, unit: "ks" }, }); itemBId = itemB.id; }); afterAll(async () => { if (app) await app.close(); await cleanup(); await prisma.$disconnect(); }); describe("GET /warehouse/items sort param", () => { it("honors sort=item_number (asc puts the A1 item first)", async () => { const res = await app.inject({ method: "GET", url: `/api/admin/warehouse/items?search=${N}&sort=item_number&order=asc`, headers: { Authorization: `Bearer ${adminToken}` }, }); expect(res.statusCode).toBe(200); const ids = (res.json().data as Array<{ id: number }>).map((r) => r.id); expect(ids).toEqual([itemBId, itemAId]); }); it("defaults to name ordering when no sort is given", async () => { const res = await app.inject({ method: "GET", url: `/api/admin/warehouse/items?search=${N}`, headers: { Authorization: `Bearer ${adminToken}` }, }); expect(res.statusCode).toBe(200); const ids = (res.json().data as Array<{ id: number }>).map((r) => r.id); expect(ids).toEqual([itemAId, itemBId]); }); it("ignores a non-allow-listed sort field (no 500)", async () => { const res = await app.inject({ method: "GET", url: `/api/admin/warehouse/items?search=${N}&sort=total_quantity`, headers: { Authorization: `Bearer ${adminToken}` }, }); expect(res.statusCode).toBe(200); }); });