import { initEmojiMock, clearEmojiMock } from 'helpers/emoji'; import waitForPromises from 'helpers/wait_for_promises'; import { createMockClient } from 'helpers/mock_apollo_helper'; import installGlEmojiElement from '~/behaviors/gl_emoji'; import { EMOJI_VERSION } from '~/emoji'; import customEmojiQuery from '~/emoji/queries/custom_emoji.query.graphql'; import * as EmojiUnicodeSupport from '~/emoji/support'; let mockClient; jest.mock('~/emoji/support'); jest.mock('~/lib/graphql', () => { return () => mockClient; }); describe('gl_emoji', () => { const emojiData = { grey_question: { c: 'symbols', e: '❔', d: 'white question mark ornament', u: '6.0', }, bomb: { c: 'objects', e: '💣', d: 'bomb', u: '6.0', }, }; beforeAll(() => { jest.spyOn(EmojiUnicodeSupport, 'default').mockReturnValue(true); installGlEmojiElement(); }); function markupToDomElement(markup) { const div = document.createElement('div'); div.innerHTML = markup; document.body.appendChild(div); return div.firstElementChild; } afterEach(() => { clearEmojiMock(); document.body.innerHTML = ''; }); describe('standard emoji', () => { beforeEach(async () => { await initEmojiMock(emojiData); }); describe.each([ [ 'bomb emoji just with name attribute', '', '💣', `:bomb:`, ], [ 'bomb emoji with name attribute and unicode version', '💣', '💣', `:bomb:`, ], [ 'bomb emoji with sprite fallback', '', '💣', '💣', ], [ 'bomb emoji with image fallback', '', '💣', ':bomb:', ], [ 'invalid emoji', '', '', `:grey_question:`, ], [ 'custom emoji with image fallback', '', ':party-parrot:', ':party-parrot:', ], ])('%s', (name, markup, withEmojiSupport, withoutEmojiSupport) => { it(`renders correctly with emoji support`, async () => { jest.spyOn(EmojiUnicodeSupport, 'default').mockReturnValue(true); const glEmojiElement = markupToDomElement(markup); await waitForPromises(); expect(glEmojiElement.outerHTML).toBe(withEmojiSupport); }); it(`renders correctly without emoji support`, async () => { jest.spyOn(EmojiUnicodeSupport, 'default').mockReturnValue(false); const glEmojiElement = markupToDomElement(markup); await waitForPromises(); expect(glEmojiElement.outerHTML).toBe(withoutEmojiSupport); }); }); it('escapes gl-emoji name', async () => { const glEmojiElement = markupToDomElement( "abc", ); await waitForPromises(); expect(glEmojiElement.outerHTML).toBe( ':"x="y" onload="alert(document.location.href)":', ); }); it('Adds sprite CSS if emojis are not supported', async () => { const testPath = '/test-path.css'; jest.spyOn(EmojiUnicodeSupport, 'default').mockReturnValue(false); window.gon.emoji_sprites_css_path = testPath; expect(document.head.querySelector(`link[href="${testPath}"]`)).toBe(null); expect(window.gon.emoji_sprites_css_added).toBe(undefined); markupToDomElement( '', ); await waitForPromises(); expect(document.head.querySelector(`link[href="${testPath}"]`).outerHTML).toBe( '', ); expect(window.gon.emoji_sprites_css_added).toBe(true); }); }); describe('custom emoji', () => { beforeEach(async () => { mockClient = createMockClient([ [ customEmojiQuery, jest.fn().mockResolvedValue({ data: { group: { id: 1, customEmoji: { nodes: [{ id: 1, name: 'parrot', url: 'parrot.gif' }], }, }, }, }), ], ]); window.gon = { features: { customEmoji: true } }; document.body.dataset.group = 'test-group'; await initEmojiMock(emojiData); }); afterEach(() => { window.gon = {}; delete document.body.dataset.group; }); it('renders custom emoji', async () => { const glEmojiElement = markupToDomElement(''); await waitForPromises(); const img = glEmojiElement.querySelector('img'); expect(glEmojiElement.dataset.unicodeVersion).toBe('custom'); expect(img.getAttribute('src')).toBe('parrot.gif'); }); }); });