addition of new dashboard
This commit is contained in:
107
backend/modules/dashboard/query.test.js
Normal file
107
backend/modules/dashboard/query.test.js
Normal file
@@ -0,0 +1,107 @@
|
||||
import {
|
||||
sortClause,
|
||||
SORTABLE_KEYS,
|
||||
eventSearchClause,
|
||||
clampLimit,
|
||||
clampOffset,
|
||||
pageCount,
|
||||
windowParams,
|
||||
DEFAULT_LIMIT,
|
||||
} from "./query.js";
|
||||
|
||||
describe("sortClause", () => {
|
||||
it("maps known keys and directions", () => {
|
||||
expect(sortClause("size", "asc")).toBe('ORDER BY "size" ASC NULLS LAST');
|
||||
expect(sortClause("sender", "desc")).toBe("ORDER BY sender DESC NULLS LAST");
|
||||
});
|
||||
|
||||
it("falls back to date DESC for unknown/missing keys", () => {
|
||||
expect(sortClause(undefined, undefined)).toBe("ORDER BY date DESC NULLS LAST");
|
||||
expect(sortClause("nope", "asc")).toBe("ORDER BY date ASC NULLS LAST");
|
||||
});
|
||||
|
||||
it("never interpolates an attacker-supplied sort key (injection safety)", () => {
|
||||
const clause = sortClause("date; DROP TABLE event; --", "asc");
|
||||
expect(clause).toBe("ORDER BY date ASC NULLS LAST");
|
||||
expect(clause).not.toMatch(/DROP TABLE/);
|
||||
});
|
||||
|
||||
it("only honors exactly 'asc' for direction, otherwise DESC", () => {
|
||||
expect(sortClause("date", "ASC")).toContain("ASC");
|
||||
expect(sortClause("date", "ascending")).toContain("DESC");
|
||||
expect(sortClause("date", "; DELETE")).toContain("DESC");
|
||||
});
|
||||
|
||||
it("exposes the sortable keys", () => {
|
||||
expect(SORTABLE_KEYS).toEqual(
|
||||
expect.arrayContaining(["agreementUuid", "eventUuid", "sender", "date", "size"]),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("eventSearchClause", () => {
|
||||
it("references the given bind index and only that index (no interpolated value)", () => {
|
||||
const c = eventSearchClause(3);
|
||||
expect(c).toContain("$3");
|
||||
expect(c).toContain("ILIKE");
|
||||
// no other positional params leak in
|
||||
expect(c.match(/\$\d+/g).every((p) => p === "$3")).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("clampLimit / clampOffset", () => {
|
||||
it("clamps limit into [1, 200] with a default", () => {
|
||||
expect(clampLimit(undefined)).toBe(DEFAULT_LIMIT);
|
||||
expect(clampLimit("abc")).toBe(DEFAULT_LIMIT);
|
||||
expect(clampLimit("0")).toBe(1);
|
||||
expect(clampLimit("-5")).toBe(1);
|
||||
expect(clampLimit("9999")).toBe(200);
|
||||
expect(clampLimit("75")).toBe(75);
|
||||
});
|
||||
|
||||
it("clamps offset to a non-negative integer", () => {
|
||||
expect(clampOffset(undefined)).toBe(0);
|
||||
expect(clampOffset("-3")).toBe(0);
|
||||
expect(clampOffset("abc")).toBe(0);
|
||||
expect(clampOffset("40")).toBe(40);
|
||||
});
|
||||
});
|
||||
|
||||
describe("pageCount", () => {
|
||||
it("computes ceil(total/perPage), at least 1", () => {
|
||||
expect(pageCount(0, 50)).toBe(1);
|
||||
expect(pageCount(50, 50)).toBe(1);
|
||||
expect(pageCount(51, 50)).toBe(2);
|
||||
expect(pageCount(200, 50)).toBe(4);
|
||||
});
|
||||
});
|
||||
|
||||
describe("windowParams", () => {
|
||||
it("defaults to a 30-day window ending today (UTC)", () => {
|
||||
const { from, to } = windowParams({});
|
||||
const days = (new Date(`${to}T00:00:00Z`) - new Date(`${from}T00:00:00Z`)) / 86_400_000;
|
||||
expect(days).toBe(29);
|
||||
expect(to).toMatch(/^\d{4}-\d{2}-\d{2}$/);
|
||||
});
|
||||
|
||||
it("honors valid from/to", () => {
|
||||
expect(windowParams({ from: "2026-01-01", to: "2026-01-31" })).toEqual({
|
||||
from: "2026-01-01",
|
||||
to: "2026-01-31",
|
||||
});
|
||||
});
|
||||
|
||||
it("ignores invalid dates and collapses inverted ranges", () => {
|
||||
expect(windowParams({ from: "not-a-date", to: "2026-02-10" }).to).toBe("2026-02-10");
|
||||
expect(windowParams({ from: "2026-05-01", to: "2026-01-01" })).toEqual({
|
||||
from: "2026-01-01",
|
||||
to: "2026-01-01",
|
||||
});
|
||||
});
|
||||
|
||||
it("caps windows wider than ~a year", () => {
|
||||
const { from, to } = windowParams({ from: "2000-01-01", to: "2026-01-01" });
|
||||
const days = (new Date(`${to}T00:00:00Z`) - new Date(`${from}T00:00:00Z`)) / 86_400_000;
|
||||
expect(days).toBeLessThanOrEqual(366);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user