94 lines
2.5 KiB
TypeScript
94 lines
2.5 KiB
TypeScript
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"]);
|
|
});
|
|
});
|