[Glitch] Emoji Component

Port c12b8f51c1 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
Echo
2025-09-30 15:06:02 +02:00
committed by Claire
parent 752214622c
commit 7430e3c74d
20 changed files with 491 additions and 301 deletions

View File

@@ -1,10 +1,6 @@
import { customEmojiFactory, unicodeEmojiFactory } from '@/testing/factories';
import {
EMOJI_MODE_NATIVE,
EMOJI_MODE_NATIVE_WITH_FLAGS,
EMOJI_MODE_TWEMOJI,
} from './constants';
import { EMOJI_MODE_TWEMOJI } from './constants';
import * as db from './database';
import {
emojifyElement,
@@ -12,7 +8,7 @@ import {
testCacheClear,
tokenizeText,
} from './render';
import type { EmojiAppState, ExtraCustomEmojiMap } from './types';
import type { EmojiAppState } from './types';
function mockDatabase() {
return {
@@ -40,18 +36,6 @@ const expectedSmileImage =
'<img draggable="false" class="emojione" alt="😊" title="smiling face with smiling eyes" src="/emoji/1f60a.svg">';
const expectedFlagImage =
'<img draggable="false" class="emojione" alt="🇪🇺" title="flag-eu" src="/emoji/1f1ea-1f1fa.svg">';
const expectedCustomEmojiImage =
'<img draggable="false" class="emojione custom-emoji" alt=":custom:" title=":custom:" src="emoji/custom/static" data-original="emoji/custom" data-static="emoji/custom/static">';
const expectedRemoteCustomEmojiImage =
'<img draggable="false" class="emojione custom-emoji" alt=":remote:" title=":remote:" src="remote.social/static" data-original="remote.social/custom" data-static="remote.social/static">';
const mockExtraCustom: ExtraCustomEmojiMap = {
remote: {
shortcode: 'remote',
static_url: 'remote.social/static',
url: 'remote.social/custom',
},
};
function testAppState(state: Partial<EmojiAppState> = {}) {
return {
@@ -86,64 +70,10 @@ describe('emojifyElement', () => {
'en',
);
expect(searchCustomEmojisByShortcodes).toHaveBeenCalledExactlyOnceWith([
'custom',
':custom:',
]);
});
test('emojifies custom emoji in native mode', async () => {
const { searchEmojisByHexcodes } = mockDatabase();
const actual = await emojifyElement(
testElement(),
testAppState({ mode: EMOJI_MODE_NATIVE }),
);
assert(actual);
expect(actual.innerHTML).toBe(
`<p>Hello 😊🇪🇺!</p><p>${expectedCustomEmojiImage}</p>`,
);
expect(searchEmojisByHexcodes).not.toHaveBeenCalled();
});
test('emojifies flag emoji in native-with-flags mode', async () => {
const { searchEmojisByHexcodes } = mockDatabase();
const actual = await emojifyElement(
testElement(),
testAppState({ mode: EMOJI_MODE_NATIVE_WITH_FLAGS }),
);
assert(actual);
expect(actual.innerHTML).toBe(
`<p>Hello 😊${expectedFlagImage}!</p><p>${expectedCustomEmojiImage}</p>`,
);
expect(searchEmojisByHexcodes).toHaveBeenCalledOnce();
});
test('emojifies everything in twemoji mode', async () => {
const { searchCustomEmojisByShortcodes, searchEmojisByHexcodes } =
mockDatabase();
const actual = await emojifyElement(testElement(), testAppState());
assert(actual);
expect(actual.innerHTML).toBe(
`<p>Hello ${expectedSmileImage}${expectedFlagImage}!</p><p>${expectedCustomEmojiImage}</p>`,
);
expect(searchEmojisByHexcodes).toHaveBeenCalledOnce();
expect(searchCustomEmojisByShortcodes).toHaveBeenCalledOnce();
});
test('emojifies with provided custom emoji', async () => {
const { searchCustomEmojisByShortcodes, searchEmojisByHexcodes } =
mockDatabase();
const actual = await emojifyElement(
testElement('<p>hi :remote:</p>'),
testAppState(),
mockExtraCustom,
);
assert(actual);
expect(actual.innerHTML).toBe(
`<p>hi ${expectedRemoteCustomEmojiImage}</p>`,
);
expect(searchEmojisByHexcodes).not.toHaveBeenCalled();
expect(searchCustomEmojisByShortcodes).not.toHaveBeenCalled();
});
test('returns null when no emoji are found', async () => {
mockDatabase();
const actual = await emojifyElement(
@@ -165,28 +95,9 @@ describe('emojifyText', () => {
const actual = await emojifyText('Hello 😊🇪🇺!', testAppState());
expect(actual).toBe(`Hello ${expectedSmileImage}${expectedFlagImage}!`);
});
test('renders custom emojis', async () => {
mockDatabase();
const actual = await emojifyText('Hello :custom:!', testAppState());
expect(actual).toBe(`Hello ${expectedCustomEmojiImage}!`);
});
test('renders provided extra emojis', async () => {
const actual = await emojifyText(
'remote emoji :remote:',
testAppState(),
mockExtraCustom,
);
expect(actual).toBe(`remote emoji ${expectedRemoteCustomEmojiImage}`);
});
});
describe('tokenizeText', () => {
test('returns empty array for string with only whitespace', () => {
expect(tokenizeText(' \n')).toEqual([]);
});
test('returns an array of text to be a single token', () => {
expect(tokenizeText('Hello')).toEqual(['Hello']);
});
@@ -212,7 +123,7 @@ describe('tokenizeText', () => {
'Hello ',
{
type: 'custom',
code: 'smile',
code: ':smile:',
},
'!!',
]);
@@ -223,7 +134,7 @@ describe('tokenizeText', () => {
'Hello ',
{
type: 'custom',
code: 'smile_123',
code: ':smile_123:',
},
'!!',
]);
@@ -239,7 +150,7 @@ describe('tokenizeText', () => {
' ',
{
type: 'custom',
code: 'smile',
code: ':smile:',
},
'!!',
]);