Files
cinny/src/app/plugins/recent-emoji.test.ts
T
jaredandClaude Opus 4.8 96f7187031 perf(audit): emojibase lazy-split, SW precache, Prism subset, lazy images
- emojibase (~965 KB) is now fully lazy: plugins/emoji.ts loads compact data +
  shortcode maps via a memoized dynamic import (rejections reset the memo so a
  mid-deploy chunk 404 can retry); reaction labels degrade to the raw glyph
  until loaded. Consumers get FRESH array references on load (the module arrays
  populate in place — same-ref state updates would skip re-render and leave
  emoji search empty; reviewer-caught). Verified out of the eager graph.
- Service worker precaches hashed assets (workbox precacheAndRoute, 82 entries
  ~10.8 MB incl. the crypto wasm): repeat visits stop re-downloading the app.
  index.html is NOT precached — navigations stay network-first so deploys are
  picked up immediately; the media-auth fetch handler is untouched.
- ReactPrism: curated 21-language set — chunk 574 KB → 71 KB.
- Timeline inline images get loading="lazy".
- Removed dead dompurify (+types); sanitize-html is the real sanitizer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 00:19:16 -04:00

118 lines
3.7 KiB
TypeScript

import { test } from 'node:test';
import assert from 'node:assert/strict';
import { MatrixClient, MatrixEvent } from 'matrix-js-sdk';
import { addRecentEmoji, getRecentEmojis, IRecentEmojiContent } from './recent-emoji';
import { AccountDataEvent } from '../../types/matrix/accountData';
import { emojis, loadEmojiData } from './emoji';
// A Map-backed MatrixClient stub supporting get/setAccountData.
const createMx = () => {
const store = new Map<string, unknown>();
const mx = {
getAccountData: (type: string): MatrixEvent | undefined => {
if (!store.has(type)) return undefined;
const content = store.get(type);
return { getContent: () => content } as unknown as MatrixEvent;
},
setAccountData: (type: string, content: unknown) => {
store.set(type, content);
return Promise.resolve({});
},
};
return { mx: mx as unknown as MatrixClient, store };
};
const getStored = (store: Map<string, unknown>): IRecentEmojiContent['recent_emoji'] =>
(store.get(AccountDataEvent.ElementRecentEmoji) as IRecentEmojiContent | undefined)?.recent_emoji;
// Emoji data is now loaded lazily; populate `emojis` before the round trips.
await loadEmojiData();
// Pick two real unicode emojis to drive add->get round trips.
const u1 = emojis[0].unicode;
const u2 = emojis[1].unicode;
test('getRecentEmojis returns [] when there is no account data', () => {
const { mx } = createMx();
assert.deepEqual(getRecentEmojis(mx), []);
});
test('getRecentEmojis returns [] when content is not an array', () => {
const { mx, store } = createMx();
store.set(AccountDataEvent.ElementRecentEmoji, { recent_emoji: 'nope' });
assert.deepEqual(getRecentEmojis(mx), []);
});
test('addRecentEmoji creates an entry with count 1', () => {
const { mx, store } = createMx();
addRecentEmoji(mx, u1);
assert.deepEqual(getStored(store), [[u1, 1]]);
});
test('adding the same emoji again increments its count and keeps it at front', () => {
const { mx, store } = createMx();
addRecentEmoji(mx, u1);
addRecentEmoji(mx, u1);
assert.deepEqual(getStored(store), [[u1, 2]]);
});
test('a newly added emoji is promoted to the front', () => {
const { mx, store } = createMx();
addRecentEmoji(mx, u1);
addRecentEmoji(mx, u2);
assert.deepEqual(getStored(store), [
[u2, 1],
[u1, 1],
]);
});
test('re-adding an existing emoji promotes it to front and increments', () => {
const { mx, store } = createMx();
addRecentEmoji(mx, u1);
addRecentEmoji(mx, u2);
addRecentEmoji(mx, u1);
assert.deepEqual(getStored(store), [
[u1, 2],
[u2, 1],
]);
});
test('list is capped at 100 entries', () => {
const { mx, store } = createMx();
for (let i = 0; i < 120; i += 1) {
addRecentEmoji(mx, `:emoji-${i}:`);
}
const stored = getStored(store)!;
assert.equal(stored.length, 100);
// most recently added is at the front
assert.equal(stored[0][0], ':emoji-119:');
});
test('getRecentEmojis resolves stored unicodes to known emoji objects', () => {
const { mx } = createMx();
addRecentEmoji(mx, u1);
addRecentEmoji(mx, u2);
const recent = getRecentEmojis(mx);
assert.equal(recent.length, 2);
assert.equal(recent[0].unicode, u2);
assert.equal(recent[1].unicode, u1);
});
test('getRecentEmojis skips unicodes with no matching emoji definition', () => {
const { mx } = createMx();
addRecentEmoji(mx, ':not-a-real-emoji:');
addRecentEmoji(mx, u1);
const recent = getRecentEmojis(mx);
assert.equal(recent.length, 1);
assert.equal(recent[0].unicode, u1);
});
test('getRecentEmojis respects the limit argument (slice before resolve)', () => {
const { mx } = createMx();
addRecentEmoji(mx, u1);
addRecentEmoji(mx, u2);
const recent = getRecentEmojis(mx, 1);
assert.equal(recent.length, 1);
assert.equal(recent[0].unicode, u2);
});