kink-discovery / frontend /board-utils.test.mjs
Perplexed7675's picture
Sync from kink_cli (Docker Space)
2c11dc3 verified
Raw
History Blame Contribute Delete
7.26 kB
/**
* Contract: optimistic board updates must never drop a rated kink when play-board cache is still empty.
* (Regression: early return when sourceItem was null left all buckets empty.)
*/
import assert from "node:assert/strict";
import test from "node:test";
import {
findBoardItemInData,
optimisticBoard,
playCommitKey,
removeKinkFromItemsPayload,
sortedBoardItems,
} from "./board-utils.js";
test("sortedBoardItems orders by popularity descending then name ascending without mutating input", () => {
const input = [
{ id: "low", name: "Zed", popularity: 5 },
{ id: "b", name: "Beta", popularity: 10 },
{ id: "a", name: "Alpha", popularity: 10 },
];
assert.deepEqual(sortedBoardItems(input).map((item) => item.id), ["a", "b", "low"]);
assert.deepEqual(input.map((item) => item.id), ["low", "b", "a"]);
});
test("optimisticBoard places stub when no server board and no query cache", () => {
const b = optimisticBoard(null, "fetlife_999", "like", ["by_me", "to_me"], null, null);
const inTo = b.to_me.some((x) => x.id === "fetlife_999");
const inBy = b.by_me.some((x) => x.id === "fetlife_999");
assert.ok(inTo && inBy, "stub row must appear in every direction bucket requested");
});
test("optimisticBoard removes stale copies and routes hard_no / not_interested to private buckets", () => {
const previous = {
to_me: [{ id: "k1", name: "Alpha", popularity: 1 }],
by_me: [{ id: "k1", name: "Alpha", popularity: 1 }],
together: [{ id: "k2", name: "Beta", popularity: 2 }],
hidden: [],
no_go: [],
};
const hidden = optimisticBoard(previous, "k1", "not_interested", ["to_me"], null, null);
assert.deepEqual(hidden.to_me, []);
assert.deepEqual(hidden.by_me, []);
assert.deepEqual(hidden.hidden.map((item) => item.id), ["k1"]);
const noGo = optimisticBoard(previous, "k1", "hard_no", ["to_me"], null, null);
assert.deepEqual(noGo.to_me, []);
assert.deepEqual(noGo.by_me, []);
assert.deepEqual(noGo.no_go.map((item) => item.id), ["k1"]);
});
test("optimisticBoard uses together when positive directions are empty", () => {
const b = optimisticBoard(null, "k1", "love", [], null, null);
assert.deepEqual(b.together.map((item) => item.id), ["k1"]);
assert.deepEqual(b.to_me, []);
assert.deepEqual(b.by_me, []);
});
test("optimisticBoard can hydrate item details from query caches", () => {
const queries = [
{ queryKey: ["search", "Bond"], state: { data: { items: [{ kink: { id: "k1", name: "Bondage", definition: "Fixture", popularity: 42 } }] } } },
];
const qc = {
getQueryData(key) {
if (JSON.stringify(key) === JSON.stringify(["kink", "k2"])) {
return { id: "k2", name: "Spanking", detail_summary: "Fixture", popularity: 11 };
}
return null;
},
getQueryCache() {
return { findAll: ({ predicate }) => queries.filter(predicate) };
},
};
const fromSearch = optimisticBoard(null, "k1", "like", ["to_me"], qc, { userId: "u1" });
assert.deepEqual(fromSearch.to_me[0], {
id: "k1",
name: "Bondage",
summary: "Fixture",
popularity: 42,
interest_state: "like",
directions: ["to_me"],
});
const fromDetail = optimisticBoard(null, "k2", "like", ["by_me"], qc, { userId: "u1" });
assert.equal(fromDetail.by_me[0].name, "Spanking");
assert.equal(fromDetail.by_me[0].summary, "Fixture");
});
test("optimisticBoard hydrates from scoped rec and prompt caches before falling back to global scans", () => {
const scoped = new Map([
[
JSON.stringify(["recs", "u1", ""]),
{ items: [{ kink: { id: "rec-hit", name: "Rec Hit", summary: "rec", popularity: 9 } }] },
],
[
JSON.stringify(["prompts", "u1", ""]),
{ items: [{ kink: { id: "prompt-hit", name: "Prompt Hit", definition: "prompt", popularity: 8 } }] },
],
]);
const qc = {
getQueryData(key) {
return scoped.get(JSON.stringify(key)) || null;
},
getQueryCache() {
return { findAll: () => [] };
},
};
const fromRec = optimisticBoard(null, "rec-hit", "like", ["to_me"], qc, { userId: "u1" });
const fromPrompt = optimisticBoard(null, "prompt-hit", "like", ["by_me"], qc, { userId: "u1" });
assert.equal(fromRec.to_me[0].name, "Rec Hit");
assert.equal(fromRec.to_me[0].summary, "rec");
assert.equal(fromPrompt.by_me[0].name, "Prompt Hit");
assert.equal(fromPrompt.by_me[0].summary, "prompt");
});
test("optimisticBoard hydrates from group-overlap direct and similar caches only", () => {
const queries = [
{
queryKey: ["group-overlap", "u1", "g1"],
state: {
data: {
direct_matches: [{ id: "direct-hit", name: "Direct Hit", summary: "direct", popularity: 7 }],
similar_matches: [{ kink: { id: "similar-hit", name: "Similar Hit", detail_summary: "similar", popularity: 6 } }],
},
},
},
{
queryKey: ["other", "u1"],
state: {
data: {
direct_matches: [{ id: "wrong-hit", name: "Wrong Hit", popularity: 99 }],
},
},
},
];
const qc = {
getQueryData() {
return null;
},
getQueryCache() {
return { findAll: ({ predicate }) => queries.filter(predicate) };
},
};
const direct = optimisticBoard(null, "direct-hit", "love", ["together"], qc, { userId: "u1" });
const similar = optimisticBoard(null, "similar-hit", "like", ["to_me"], qc, { userId: "u1" });
const wrong = optimisticBoard(null, "wrong-hit", "like", ["by_me"], qc, { userId: "u1" });
assert.equal(direct.together[0].name, "Direct Hit");
assert.equal(direct.together[0].summary, "direct");
assert.equal(similar.to_me[0].name, "Similar Hit");
assert.equal(similar.to_me[0].summary, "similar");
assert.equal(wrong.by_me[0].name, "wrong-hit");
});
test("findBoardItemInData scans every bucket and tolerates missing boards", () => {
const board = {
to_me: [],
by_me: [{ id: 7, name: "Seven" }],
together: [],
hidden: [],
no_go: [],
};
assert.equal(findBoardItemInData(null, 7), null);
assert.deepEqual(findBoardItemInData(board, "7"), { id: 7, name: "Seven" });
});
test("removeKinkFromItemsPayload filters by kink id while preserving payload metadata", () => {
const payload = {
cursor: "next",
items: [{ kink: { id: "keep" } }, { kink: { id: 12 } }, { kink: { id: "12" } }],
};
assert.equal(removeKinkFromItemsPayload(null, "x"), null);
assert.deepEqual(removeKinkFromItemsPayload(payload, 12), {
cursor: "next",
items: [{ kink: { id: "keep" } }],
});
});
test("removeKinkFromItemsPayload preserves malformed rows that are not the removed kink", () => {
const payload = {
items: [
{},
{ kink: null },
{ kink: { id: "remove" } },
{ kink: { id: "keep" } },
],
};
assert.deepEqual(removeKinkFromItemsPayload(payload, "remove"), {
items: [{}, { kink: null }, { kink: { id: "keep" } }],
});
});
test("playCommitKey is stable for direction ordering and empty directions", () => {
assert.equal(playCommitKey("k1", "like", ["by_me", "to_me"]), "k1::like::by_me|to_me");
assert.equal(playCommitKey("k1", "like", ["to_me", "by_me"]), "k1::like::by_me|to_me");
assert.equal(playCommitKey("k1", "hard_no"), "k1::hard_no::");
});