05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 1 | import assert from 'node:assert/strict'; |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 2 | import { test } from 'node:test'; |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 3 | import { completeShortcode, emoteQueryAt, rankEmotes, resolveEmotes } from '../src/lib/emotes.ts'; |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 4 | import { formatBody } from '../src/lib/markdown.ts'; |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 5 | |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 6 | const sob = { emoji: 'π', label: 'loudly crying face', tags: [], shortcodes: ['sob'] }; |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 7 | const smile = { emoji: 'π', label: 'grinning face with smiling eyes', tags: [], shortcodes: ['smile'] }; |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 8 | const blob = { shortcode: 'blob_sob', mxc: 'mxc://example.org/blob' }; |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 9 | |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 10 | test('opens the emote query after two shortcode characters at a word start', () => { |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 11 | assert.deepEqual(emoteQueryAt('so :so', 6), { start: 3, query: 'so' }); |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 12 | assert.equal(emoteQueryAt('so :s', 5), null); |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 13 | assert.equal(emoteQueryAt('re:so', 5), null); |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 14 | assert.equal(emoteQueryAt('12:30', 5), null); |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 15 | assert.equal(emoteQueryAt(':so b', 5), null); |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 16 | }); |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 17 | |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 18 | test('ranks prefix matches ahead of word and substring matches', () => { |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 19 | const names = rankEmotes('sob', [blob], [sob, smile]).map((c) => c.shortcode); |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 20 | assert.deepEqual(names, ['sob', 'blob_sob']); |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 21 | }); |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 22 | |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 23 | test('swaps a closed emoji shortcode for the emoji', () => { |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 24 | assert.deepEqual(completeShortcode('ugh :sob:', 9, [sob]), { text: 'ugh π', caret: 6 }); |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 25 | assert.equal(completeShortcode('ugh :blob_sob:', 14, [sob]), null); |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 26 | assert.equal(completeShortcode('a:sob:', 6, [sob]), null); |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 27 | }); |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 28 | |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 29 | test('sends used custom emotes as emoticon images', () => { |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 30 | const emotes = resolveEmotes('hi :blob_sob: and :nope:', [blob]); |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 31 | assert.deepEqual(emotes, [blob]); |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 32 | assert.equal( |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 33 | formatBody('hi :blob_sob:', [], false, emotes), |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 34 | 'hi <img data-mx-emoticon src="mxc://example.org/blob" alt=":blob_sob:" title=":blob_sob:" height="32">' |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 35 | ); |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 36 | assert.match(formatBody('**hi** :blob_sob:', [], true, emotes) ?? '', /<strong>hi<\/strong> <img data-mx-emoticon/); |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 37 | assert.equal(formatBody('`:blob_sob:`', [], true, emotes), '<p><code>:blob_sob:</code></p>'); |
05a48e9e7942 | atagen | 2026-10-24 09:32 UTC | 38 | }); |