feat(blog): limit rapid repeat views

This commit is contained in:
DeCentN2Madness committed 2026-11-06 14:05:37 -07:00
1 parent 96288b1eb8
commit eeff641a1d
3 files changed
+85 -2

No files matched your search

+37
View File
@@ -5,10 +5,12 @@ import test from 'node:test';
import fg from 'fast-glob';
import matter from 'gray-matter';
import {
articleViewCooldownMs,
bindLiveCounters,
fetchCounterStats,
readLikedSlugs,
reportArticleView,
reserveArticleView,
updateLike,
} from '../src/scripts/likes-views.ts';
@@ -139,6 +141,41 @@ test('one article navigation increments once while cards only retrieve statistic
assert.deepEqual([...readLikedSlugs(storage)], []);
});
test('a short per-tab cooldown suppresses back-navigation duplicates and then expires', async () => {
const likeStorage = new FakeStorage();
const viewStorage = new FakeStorage();
const calls = [];
const fetcher = async (url) => {
calls.push(url);
return response(url.endsWith('/views')
? { views: 21 }
: { 'shared-slug': { likes: 4, views: 20 } });
};
await bindLiveCounters(new FakeRoot([new FakeCounter('shared-slug', { trackView: true })]), fetcher, likeStorage, viewStorage);
await bindLiveCounters(new FakeRoot([new FakeCounter('shared-slug', { trackView: true })]), fetcher, likeStorage, viewStorage);
assert.equal(calls.filter((url) => url.endsWith('/views')).length, 1);
const clockStorage = new FakeStorage();
assert.equal(reserveArticleView('shared-slug', clockStorage, 10_000), true);
assert.equal(reserveArticleView('shared-slug', clockStorage, 10_000 + articleViewCooldownMs - 1), false);
assert.equal(reserveArticleView('shared-slug', clockStorage, 10_000 + articleViewCooldownMs), true);
assert.equal(reserveArticleView('different-slug', clockStorage, 10_000 + articleViewCooldownMs), true);
});
test('invalid or unavailable session storage fails open without persisting an identifier', () => {
const corrupt = new FakeStorage();
corrupt.setItem('aia-view-cooldowns-v1', '{broken');
assert.equal(reserveArticleView('article', corrupt, 10_000), true);
assert.deepEqual(JSON.parse(corrupt.getItem('aia-view-cooldowns-v1')), { article: 10_000 });
const blocked = {
getItem() { throw new Error('blocked'); },
setItem() { throw new Error('blocked'); },
};
assert.equal(reserveArticleView('article', blocked, 10_000), true);
});
test('API failures preserve rendering and expose localized inline status', async () => {
const counter = new FakeCounter('article', { trackView: true, lang: 'ar' });
const root = new FakeRoot([counter]);