544a170ead2c | atagen | 2026-10-20 11:47 UTC | 1 | import assert from 'node:assert/strict'; |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 2 | import { test } from 'node:test'; |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 3 | import { isJumbo, segmentEmoji, twemojiUrl } from '../src/lib/twemoji.ts'; |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 4 | |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 5 | const emojiOf = (text: string) => segmentEmoji(text).filter((s) => s.emoji).map((s) => s.text); |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 6 | |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 7 | test('plain text takes the fast path', () => { |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 8 | assert.deepEqual(segmentEmoji('hello world 123 #1 *'), [{ text: 'hello world 123 #1 *', emoji: false }]); |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 9 | }); |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 10 | |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 11 | test('splits text and emoji', () => { |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 12 | assert.deepEqual(segmentEmoji('hi ๐ there'), [ |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 13 | { text: 'hi ', emoji: false }, |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 14 | { text: '๐', emoji: true }, |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 15 | { text: ' there', emoji: false } |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 16 | ]); |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 17 | }); |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 18 | |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 19 | test('keeps ZWJ sequences whole', () => { |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 20 | assert.deepEqual(emojiOf('a ๐ฉโ๐ป b ๐จโ๐ฉโ๐งโ๐ฆ'), ['๐ฉโ๐ป', '๐จโ๐ฉโ๐งโ๐ฆ']); |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 21 | }); |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 22 | |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 23 | test('keeps skin tones whole', () => { |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 24 | assert.deepEqual(emojiOf('๐๐ฝ'), ['๐๐ฝ']); |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 25 | }); |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 26 | |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 27 | test('treats a regional indicator pair as one flag', () => { |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 28 | assert.deepEqual(emojiOf('๐ณ๐ฟ and ๐ฏ๐ต'), ['๐ณ๐ฟ', '๐ฏ๐ต']); |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 29 | }); |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 30 | |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 31 | test('keycaps need FE0F and 20E3', () => { |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 32 | assert.deepEqual(emojiOf('1๏ธโฃ #๏ธโฃ'), ['1๏ธโฃ', '#๏ธโฃ']); |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 33 | assert.deepEqual(emojiOf('1 # *'), []); |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 34 | }); |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 35 | |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 36 | test('text presentation symbols stay text without FE0F', () => { |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 37 | assert.deepEqual(emojiOf('ยฉ ยฎ โบ'), []); |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 38 | assert.deepEqual(emojiOf('โบ๏ธ'), ['โบ๏ธ']); |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 39 | }); |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 40 | |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 41 | test('jumbo only for one to three emoji', () => { |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 42 | assert.equal(isJumbo(segmentEmoji('๐')), true); |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 43 | assert.equal(isJumbo(segmentEmoji('๐ ๐๐')), true); |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 44 | assert.equal(isJumbo(segmentEmoji('๐๐๐๐')), false); |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 45 | assert.equal(isJumbo(segmentEmoji('hi ๐')), false); |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 46 | assert.equal(isJumbo(segmentEmoji('hello')), false); |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 47 | }); |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 48 | |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 49 | test('twemojiUrl follows the filename rule', () => { |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 50 | assert.equal(twemojiUrl('๐'), '/twemoji/1f389.svg'); |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 51 | assert.equal(twemojiUrl('โค๏ธ'), '/twemoji/2764.svg'); |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 52 | assert.equal(twemojiUrl('๐จโโ๏ธ'), '/twemoji/1f468-200d-2695-fe0f.svg'); |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 53 | assert.equal(twemojiUrl('1๏ธโฃ'), '/twemoji/31-20e3.svg'); |
544a170ead2c | atagen | 2026-10-20 11:47 UTC | 54 | }); |