feat: add extensive test suite
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { plannedOrderUpdates } from "./order";
|
||||
import { reorderService } from "./reorder-service";
|
||||
|
||||
const items = [
|
||||
{ id: "a", order: 10 },
|
||||
{ id: "b", order: 20 },
|
||||
{ id: "c", order: 30 },
|
||||
];
|
||||
|
||||
describe("plannedOrderUpdates", () => {
|
||||
test("uses a midpoint when sufficient order space exists", () => {
|
||||
expect(plannedOrderUpdates(items, ["b", "a", "c"], "a", "stale")).toEqual([
|
||||
{ id: "a", order: 25 },
|
||||
]);
|
||||
});
|
||||
|
||||
test("normalizes every item when adjacent orders have no midpoint", () => {
|
||||
expect(
|
||||
plannedOrderUpdates(
|
||||
[
|
||||
{ id: "a", order: 1 },
|
||||
{ id: "b", order: 2 },
|
||||
{ id: "c", order: 3 },
|
||||
],
|
||||
["b", "a", "c"],
|
||||
"a",
|
||||
"stale",
|
||||
),
|
||||
).toEqual([
|
||||
{ id: "b", order: 10 },
|
||||
{ id: "a", order: 20 },
|
||||
{ id: "c", order: 30 },
|
||||
]);
|
||||
});
|
||||
|
||||
test.each([
|
||||
{ ids: [] as string[] },
|
||||
{ ids: ["a", "a", "c"] },
|
||||
{ ids: ["a", "b"] },
|
||||
{ ids: ["a", "b", "stale"] },
|
||||
{ ids: ["a", "b", "c", "extra"] },
|
||||
])("rejects malformed, duplicate, or stale IDs: %p", ({ ids }) => {
|
||||
expect(() => plannedOrderUpdates(items, ids, "a", "refresh")).toThrow(
|
||||
"refresh",
|
||||
);
|
||||
});
|
||||
|
||||
test("rejects an active ID absent from an otherwise valid order", () => {
|
||||
expect(() =>
|
||||
plannedOrderUpdates(items, ["a", "b", "c"], "missing", "stale"),
|
||||
).toThrow("Moved item is missing");
|
||||
});
|
||||
});
|
||||
|
||||
describe("reorderService", () => {
|
||||
test("requires admin before opening a transaction", async () => {
|
||||
let transactionCalled = false;
|
||||
expect(
|
||||
reorderService("a", ["a"], "stale", {
|
||||
adminCheck: async () => false,
|
||||
transaction: async (callback) => {
|
||||
transactionCalled = true;
|
||||
return callback({
|
||||
list: async () => [],
|
||||
update: async () => {},
|
||||
});
|
||||
},
|
||||
afterReorder: async () => {},
|
||||
}),
|
||||
).rejects.toBe("Unauthorized");
|
||||
expect(transactionCalled).toBe(false);
|
||||
});
|
||||
|
||||
test("applies planned updates atomically before side effects", async () => {
|
||||
const calls: string[] = [];
|
||||
await reorderService("a", ["b", "a", "c"], "stale", {
|
||||
adminCheck: async () => true,
|
||||
transaction: async (callback) => {
|
||||
await callback({
|
||||
list: async () => items,
|
||||
update: async (id, order) => {
|
||||
calls.push(`update:${id}:${order}`);
|
||||
},
|
||||
});
|
||||
},
|
||||
afterReorder: async () => {
|
||||
calls.push("after");
|
||||
},
|
||||
});
|
||||
expect(calls).toEqual(["update:a:25", "after"]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user