Files
bitvid/tests/author-moderation-override.test.mjs
thePR0M3TH3ANandClaude Opus 4.8 a0131c718e Safety: account-level (per-creator) web-of-trust overrides
Add "trusted creator" overrides that suppress the web-of-trust warning/blur
for ALL of a creator's videos until reset — the account-level companion to the
existing per-video "Show anyway".

- cache.js: per-author override store (bitvid:moderationAuthorOverrides:v1),
  keyed by author hex, with get/set/has/clear/list + persist/load, mirroring
  the per-video store.
- moderationDecorator: overrideActive now also honors an account-level override
  for the video's author, so the whole class of WoT warnings clears for every
  video by that creator.
- app.js: load the author overrides on startup.
- Services + contract: getAuthorModerationOverrides / setAuthorModerationOverride
  / clearAuthorModerationOverride; set/clear refresh the feed + fire the shared
  moderation-override event so the Safety tab list updates.
- Safety tab: a "Trusted creators" section — add by npub, list each with a
  Reset, mirroring the Active-overrides section.
- tests: storage set/get/has/clear/list, hex normalization, persist→load,
  invalid-input guard.

Next: the "Always show this creator" button on the video warning overlay
(second entry point) — a larger multi-component UI change, done separately.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-08 15:58:10 -04:00

63 lines
2.3 KiB
JavaScript

import "./test-helpers/setup-localstorage.mjs";
import test, { beforeEach } from "node:test";
import assert from "node:assert/strict";
import {
setAuthorModerationOverride,
getAuthorModerationOverride,
hasAuthorModerationOverride,
clearAuthorModerationOverride,
getAuthorModerationOverridesList,
loadAuthorModerationOverridesFromStorage,
} from "../js/state/cache.js";
const HEX = "a".repeat(64);
const HEX2 = "b".repeat(64);
beforeEach(() => {
localStorage.clear();
clearAuthorModerationOverride(HEX);
clearAuthorModerationOverride(HEX2);
});
test("set + get + has recognizes an account-level override", () => {
const entry = setAuthorModerationOverride(HEX, { showAnyway: true });
assert.equal(entry.authorPubkey, HEX);
assert.equal(entry.showAnyway, true);
assert.equal(hasAuthorModerationOverride(HEX), true);
assert.equal(getAuthorModerationOverride(HEX)?.showAnyway, true);
assert.equal(hasAuthorModerationOverride(HEX2), false);
});
test("hex input is normalized (uppercase accepted, stored lowercase)", () => {
setAuthorModerationOverride(HEX.toUpperCase(), { showAnyway: true });
assert.equal(hasAuthorModerationOverride(HEX), true, "uppercase resolves to the same entry");
});
test("clearing removes it; showAnyway:false is treated as a removal", () => {
setAuthorModerationOverride(HEX, { showAnyway: true });
assert.equal(clearAuthorModerationOverride(HEX), true);
assert.equal(hasAuthorModerationOverride(HEX), false);
setAuthorModerationOverride(HEX, { showAnyway: true });
assert.equal(setAuthorModerationOverride(HEX, { showAnyway: false }), null);
assert.equal(hasAuthorModerationOverride(HEX), false);
});
test("survives a reload via persist → load roundtrip", () => {
setAuthorModerationOverride(HEX, { showAnyway: true });
setAuthorModerationOverride(HEX2, { showAnyway: true });
// A reload repopulates the in-memory map from localStorage.
loadAuthorModerationOverridesFromStorage();
const list = getAuthorModerationOverridesList()
.map((entry) => entry.authorPubkey)
.sort();
assert.deepEqual(list, [HEX, HEX2].sort());
});
test("blank/invalid pubkey is ignored", () => {
assert.equal(setAuthorModerationOverride("", { showAnyway: true }), null);
assert.equal(setAuthorModerationOverride("not-a-key", { showAnyway: true }), null);
assert.equal(getAuthorModerationOverridesList().length, 0);
});