Files
bitvid/tests/channel-video-merge.test.mjs
T
thePR0M3TH3ANandClaude Opus 4.8 f05ba5edf9 channel: union live fetch with known events so the grid never shrinks
loadUserVideos rendered only the live relay fetch, and the render REPLACES the
grid container. So when a relay holding a creator's video transiently failed or
EOSE'd late, that video disappeared from the wall even though it was already
known in memory/cache — the "channel doesn't pull in all of a creator's videos"
bug (#20, symptom 1).

Union the live events with the already-known author events
(mergeChannelVideoSources, live wins on id collision) before building the
renderable list, so the rendered set is a superset and can't shrink on a
transient relay gap. Existing dedupe-by-root + access/delete filtering still
decide precedence downstream, so newer versions and deletions still win.

Helper + tests live in channelProfileVideos.js (channelProfile.js is at its
size cap); the call site stays net-zero. Streaming/first-relay-wins render is
still the separate 17d UX follow-up.

Regression: tests/channel-video-merge.test.mjs.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-24 08:19:37 -04:00

53 lines
2.2 KiB
JavaScript

// Regression (#20): the channel grid render replaces the container with the live
// fetch, so a transiently-failing relay produced a smaller set and previously-
// known videos vanished ("some of a creator's videos are missing"). The live
// fetch must be unioned with already-known events so the grid never shrinks.
import assert from "node:assert/strict";
import test from "node:test";
import { mergeChannelVideoSources } from "../js/channelProfileVideos.js";
const ev = (id, extra = {}) => ({ id, kind: 30078, ...extra });
test("union is a superset of both live and known events", () => {
const live = [ev("a"), ev("b")];
const known = [ev("b"), ev("c"), ev("d")];
const merged = mergeChannelVideoSources(live, known);
const ids = merged.map((e) => e.id).sort();
assert.deepEqual(ids, ["a", "b", "c", "d"], "all unique ids from both sources");
});
test("a known video missing from the live fetch still appears (the bug)", () => {
// The live fetch this load only returned one video; the other is known in
// memory (e.g. from a prior load / the main feed). It must not disappear.
const live = [ev("only-live")];
const known = [ev("only-live"), ev("dropped-by-slow-relay")];
const merged = mergeChannelVideoSources(live, known);
const ids = merged.map((e) => e.id).sort();
assert.deepEqual(ids, ["dropped-by-slow-relay", "only-live"]);
});
test("live wins on id collision (freshest copy)", () => {
const live = [ev("x", { created_at: 200, source: "live" })];
const known = [ev("x", { created_at: 100, source: "cache" })];
const merged = mergeChannelVideoSources(live, known);
assert.equal(merged.length, 1);
assert.equal(merged[0].source, "live", "live copy must win the dedupe");
});
test("preserves id-less entries and tolerates non-array / junk input", () => {
const live = [ev("a"), { kind: 30078 /* no id */ }, null, "junk"];
const merged = mergeChannelVideoSources(live, undefined);
const withId = merged.filter((e) => e && e.id === "a");
const withoutId = merged.filter((e) => e && typeof e === "object" && !e.id);
assert.equal(withId.length, 1);
assert.equal(withoutId.length, 1, "id-less event kept, not dropped");
assert.deepEqual(mergeChannelVideoSources(null, null), []);
});