aboutsummaryrefslogtreecommitdiffstats
path: root/tools/feed-window-test.js
diff options
context:
space:
mode:
Diffstat (limited to 'tools/feed-window-test.js')
-rw-r--r--tools/feed-window-test.js55
1 files changed, 55 insertions, 0 deletions
diff --git a/tools/feed-window-test.js b/tools/feed-window-test.js
new file mode 100644
index 0000000..64e8364
--- /dev/null
+++ b/tools/feed-window-test.js
@@ -0,0 +1,55 @@
+// Geometry/state regressions that don't require browser or network access.
+// Run: bun tools/feed-window-test.js
+import assert from 'node:assert/strict';
+import { mergeFeedWindow } from '../src/feed-window.js';
+const note = (id, at) => ({ id, created_at: at });
+const notes = [note('a', 100), note('b', 90), note('c', 80), note('d', 70)];
+const rows = (top) => notes.map((e, i) => ({ id: e.id, top: top + i * 200, bottom: top + (i + 1) * 200 }));
+const above = note('above', 110), gap = note('gap', 95), below = note('below', 60);
+const check = (name, fn) => { fn(); console.log('✓ ' + name); };
+check('header-visible arrivals wait without changing the displayed window', () => {
+ const r = mergeFeedWindow(notes, 4, [above, gap], { rows: rows(180), height: 844 });
+ assert.equal(r.notes, notes);
+ assert.equal(r.shown, 4);
+ assert.deepEqual(r.deferred, [above, gap]);
+});
+check('offscreen prepends preserve every displayed post; visible gap fills wait', () => {
+ const r = mergeFeedWindow(notes, 4, [above, gap, below], { rows: rows(-50), height: 844 });
+ assert.deepEqual(r.added, [above, below]);
+ assert.deepEqual(r.deferred, [gap]);
+ assert.deepEqual(r.notes.slice(0, r.shown).map((e) => e.id), ['above', 'a', 'b', 'c', 'd']);
+});
+check('a deferred gap becomes available once it is above the viewport', () => {
+ const r = mergeFeedWindow(notes, 4, [gap], { rows: rows(-450), height: 844 });
+ assert.deepEqual(r.deferred, []);
+ assert.deepEqual(r.notes.map((e) => e.id), ['a', 'gap', 'b', 'c', 'd']);
+});
+check('hidden posts cannot allow an insertion between visible posts', () => {
+ const r = mergeFeedWindow([notes[0], note('hidden', 97), ...notes.slice(1)], 4, [note('gap', 98)], { rows: rows(-50), height: 844 });
+ assert.equal(r.added.length, 0);
+ assert.equal(r.deferred.length, 1);
+});
+check('equal timestamps retain their order and obey the visible-gap rule', () => {
+ const r = mergeFeedWindow(notes, 4, [note('equal', 100)], { rows: rows(-50), height: 844 });
+ assert.equal(r.added.length, 0);
+ assert.equal(r.deferred[0].id, 'equal');
+});
+check('large catch-ups retain the reader at the cache boundary', () => {
+ const old = Array.from({ length: 200 }, (_, i) => note('old' + i, 1000 - i));
+ const news = Array.from({ length: 80 }, (_, i) => note('new' + i, 2000 - i));
+ const r = mergeFeedWindow(old, 200, news);
+ assert.equal(r.shown, 280);
+ assert.equal(r.notes.at(-1).id, 'old199');
+});
+check('older-page requests still advance beyond the cache boundary', () => {
+ const old = Array.from({ length: 200 }, (_, i) => note('old' + i, 1000 - i));
+ const older = Array.from({ length: 40 }, (_, i) => note('older' + i, 500 - i));
+ const r = mergeFeedWindow(old, 200, older);
+ assert.equal(r.notes.length, 220);
+ assert.equal(r.notes[200].id, 'older0');
+});
+check('duplicate arrivals cannot create repeated rows', () => {
+ const r = mergeFeedWindow(notes, 4, [notes[0], above, above]);
+ assert.equal(r.notes.length, 5);
+ assert.deepEqual(r.added, [above]);
+});