Emoji Rendering Efficiency (#35568)

This commit is contained in:
Echo
2025-07-31 19:30:14 +02:00
committed by GitHub
parent 0e249cba4b
commit 6bca52453a
23 changed files with 954 additions and 333 deletions

View File

@@ -1,94 +1,184 @@
import { customEmojiFactory, unicodeEmojiFactory } from '@/testing/factories';
import {
EMOJI_MODE_NATIVE,
EMOJI_MODE_NATIVE_WITH_FLAGS,
EMOJI_MODE_TWEMOJI,
} from './constants';
import { emojifyElement, tokenizeText } from './render';
import type { CustomEmojiData, UnicodeEmojiData } from './types';
import * as db from './database';
import {
emojifyElement,
emojifyText,
testCacheClear,
tokenizeText,
} from './render';
import type { EmojiAppState, ExtraCustomEmojiMap } from './types';
vitest.mock('./database', () => ({
searchCustomEmojisByShortcodes: vitest.fn(
() =>
[
{
shortcode: 'custom',
static_url: 'emoji/static',
url: 'emoji/custom',
category: 'test',
visible_in_picker: true,
},
] satisfies CustomEmojiData[],
),
searchEmojisByHexcodes: vitest.fn(
() =>
[
{
function mockDatabase() {
return {
searchCustomEmojisByShortcodes: vi
.spyOn(db, 'searchCustomEmojisByShortcodes')
.mockResolvedValue([customEmojiFactory()]),
searchEmojisByHexcodes: vi
.spyOn(db, 'searchEmojisByHexcodes')
.mockResolvedValue([
unicodeEmojiFactory({
hexcode: '1F60A',
group: 0,
label: 'smiling face with smiling eyes',
order: 0,
tags: ['smile', 'happy'],
unicode: '😊',
},
{
}),
unicodeEmojiFactory({
hexcode: '1F1EA-1F1FA',
group: 0,
label: 'flag-eu',
order: 0,
tags: ['flag', 'european union'],
unicode: '🇪🇺',
},
] satisfies UnicodeEmojiData[],
),
findMissingLocales: vitest.fn(() => []),
}));
}),
]),
};
}
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 {
locales: ['en'],
mode: EMOJI_MODE_TWEMOJI,
currentLocale: 'en',
darkTheme: false,
...state,
} satisfies EmojiAppState;
}
describe('emojifyElement', () => {
const testElement = document.createElement('div');
testElement.innerHTML = '<p>Hello 😊🇪🇺!</p><p>:custom:</p>';
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/static" data-original="emoji/custom" data-static="emoji/static">';
function cloneTestElement() {
return testElement.cloneNode(true) as HTMLElement;
function testElement(text = '<p>Hello 😊🇪🇺!</p><p>:custom:</p>') {
const testElement = document.createElement('div');
testElement.innerHTML = text;
return testElement;
}
afterEach(() => {
testCacheClear();
vi.restoreAllMocks();
});
test('caches element rendering results', async () => {
const { searchCustomEmojisByShortcodes, searchEmojisByHexcodes } =
mockDatabase();
await emojifyElement(testElement(), testAppState());
await emojifyElement(testElement(), testAppState());
await emojifyElement(testElement(), testAppState());
expect(searchEmojisByHexcodes).toHaveBeenCalledExactlyOnceWith(
['1F1EA-1F1FA', '1F60A'],
'en',
);
expect(searchCustomEmojisByShortcodes).toHaveBeenCalledExactlyOnceWith([
'custom',
]);
});
test('emojifies custom emoji in native mode', async () => {
const emojifiedElement = await emojifyElement(cloneTestElement(), {
locales: ['en'],
mode: EMOJI_MODE_NATIVE,
currentLocale: 'en',
});
expect(emojifiedElement.innerHTML).toBe(
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 emojifiedElement = await emojifyElement(cloneTestElement(), {
locales: ['en'],
mode: EMOJI_MODE_NATIVE_WITH_FLAGS,
currentLocale: 'en',
});
expect(emojifiedElement.innerHTML).toBe(
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 emojifiedElement = await emojifyElement(cloneTestElement(), {
locales: ['en'],
mode: EMOJI_MODE_TWEMOJI,
currentLocale: 'en',
});
expect(emojifiedElement.innerHTML).toBe(
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(
testElement('<p>here is just text :)</p>'),
testAppState(),
);
expect(actual).toBeNull();
});
});
describe('emojifyText', () => {
test('returns original input when no emoji are in string', async () => {
const actual = await emojifyText('nothing here', testAppState());
expect(actual).toBe('nothing here');
});
test('renders Unicode emojis to twemojis', async () => {
mockDatabase();
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}`);
});
});