mirror of
https://github.com/mastodon/mastodon.git
synced 2025-10-05 00:22:42 +00:00

Some checks failed
Check i18n / check-i18n (push) Waiting to run
Chromatic / Run Chromatic (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (ruby) (push) Waiting to run
Check formatting / lint (push) Waiting to run
JavaScript Linting / lint (push) Waiting to run
Ruby Linting / lint (push) Waiting to run
JavaScript Testing / test (push) Waiting to run
Historical data migration test / test (14-alpine) (push) Waiting to run
Historical data migration test / test (15-alpine) (push) Waiting to run
Historical data migration test / test (16-alpine) (push) Waiting to run
Historical data migration test / test (17-alpine) (push) Waiting to run
Ruby Testing / build (production) (push) Waiting to run
Ruby Testing / build (test) (push) Waiting to run
Ruby Testing / test (.ruby-version) (push) Blocked by required conditions
Ruby Testing / test (3.2) (push) Blocked by required conditions
Ruby Testing / test (3.3) (push) Blocked by required conditions
Ruby Testing / ImageMagick tests (.ruby-version) (push) Blocked by required conditions
Ruby Testing / ImageMagick tests (3.2) (push) Blocked by required conditions
Ruby Testing / ImageMagick tests (3.3) (push) Blocked by required conditions
Ruby Testing / End to End testing (.ruby-version) (push) Blocked by required conditions
Ruby Testing / End to End testing (3.2) (push) Blocked by required conditions
Ruby Testing / End to End testing (3.3) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (.ruby-version, docker.elastic.co/elasticsearch/elasticsearch:7.17.13) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (.ruby-version, docker.elastic.co/elasticsearch/elasticsearch:8.10.2) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (.ruby-version, opensearchproject/opensearch:2) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (3.2, docker.elastic.co/elasticsearch/elasticsearch:7.17.13) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (3.3, docker.elastic.co/elasticsearch/elasticsearch:7.17.13) (push) Blocked by required conditions
Bundler Audit / security (push) Has been cancelled
Haml Linting / lint (push) Has been cancelled
165 lines
4.2 KiB
TypeScript
165 lines
4.2 KiB
TypeScript
import { customEmojiFactory, unicodeEmojiFactory } from '@/testing/factories';
|
|
|
|
import { EMOJI_MODE_TWEMOJI } from './constants';
|
|
import * as db from './database';
|
|
import {
|
|
emojifyElement,
|
|
emojifyText,
|
|
testCacheClear,
|
|
tokenizeText,
|
|
} from './render';
|
|
import type { EmojiAppState } from './types';
|
|
|
|
function mockDatabase() {
|
|
return {
|
|
searchCustomEmojisByShortcodes: vi
|
|
.spyOn(db, 'searchCustomEmojisByShortcodes')
|
|
.mockResolvedValue([customEmojiFactory()]),
|
|
searchEmojisByHexcodes: vi
|
|
.spyOn(db, 'searchEmojisByHexcodes')
|
|
.mockResolvedValue([
|
|
unicodeEmojiFactory({
|
|
hexcode: '1F60A',
|
|
label: 'smiling face with smiling eyes',
|
|
unicode: '😊',
|
|
}),
|
|
unicodeEmojiFactory({
|
|
hexcode: '1F1EA-1F1FA',
|
|
label: 'flag-eu',
|
|
unicode: '🇪🇺',
|
|
}),
|
|
]),
|
|
};
|
|
}
|
|
|
|
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">';
|
|
|
|
function testAppState(state: Partial<EmojiAppState> = {}) {
|
|
return {
|
|
locales: ['en'],
|
|
mode: EMOJI_MODE_TWEMOJI,
|
|
currentLocale: 'en',
|
|
darkTheme: false,
|
|
...state,
|
|
} satisfies EmojiAppState;
|
|
}
|
|
|
|
describe('emojifyElement', () => {
|
|
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('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}!`);
|
|
});
|
|
});
|
|
|
|
describe('tokenizeText', () => {
|
|
test('returns an array of text to be a single token', () => {
|
|
expect(tokenizeText('Hello')).toEqual(['Hello']);
|
|
});
|
|
|
|
test('returns tokens for text with emoji', () => {
|
|
expect(tokenizeText('Hello 😊 🇿🇼!!')).toEqual([
|
|
'Hello ',
|
|
{
|
|
type: 'unicode',
|
|
code: '😊',
|
|
},
|
|
' ',
|
|
{
|
|
type: 'unicode',
|
|
code: '🇿🇼',
|
|
},
|
|
'!!',
|
|
]);
|
|
});
|
|
|
|
test('returns tokens for text with custom emoji', () => {
|
|
expect(tokenizeText('Hello :smile:!!')).toEqual([
|
|
'Hello ',
|
|
{
|
|
type: 'custom',
|
|
code: ':smile:',
|
|
},
|
|
'!!',
|
|
]);
|
|
});
|
|
|
|
test('handles custom emoji with underscores and numbers', () => {
|
|
expect(tokenizeText('Hello :smile_123:!!')).toEqual([
|
|
'Hello ',
|
|
{
|
|
type: 'custom',
|
|
code: ':smile_123:',
|
|
},
|
|
'!!',
|
|
]);
|
|
});
|
|
|
|
test('returns tokens for text with mixed emoji', () => {
|
|
expect(tokenizeText('Hello 😊 :smile:!!')).toEqual([
|
|
'Hello ',
|
|
{
|
|
type: 'unicode',
|
|
code: '😊',
|
|
},
|
|
' ',
|
|
{
|
|
type: 'custom',
|
|
code: ':smile:',
|
|
},
|
|
'!!',
|
|
]);
|
|
});
|
|
|
|
test('does not capture custom emoji with invalid characters', () => {
|
|
expect(tokenizeText('Hello :smile-123:!!')).toEqual([
|
|
'Hello :smile-123:!!',
|
|
]);
|
|
});
|
|
});
|