diff --git a/shared/utils/emoji.ts b/shared/utils/emoji.ts index 887ce543..82fea2df 100644 --- a/shared/utils/emoji.ts +++ b/shared/utils/emoji.ts @@ -1,7 +1,6 @@ -// Regex to validate if a string contains only emoji characters -// This is not perfect but catches most common emojis -// eslint-disable-next-line -const emojiRegex = /^(?:[\p{Emoji}\u200d\u{1f1e6}-\u{1f1ff}\u{1f3fb}-\u{1f3ff}\u{1f9b0}-\u{1f9b3}])/u +// Regex to validate if a string contains exactly one emoji character (including complex emoji) +// including standard emoji, ZWJ sequences, country flags, and regional flags like Scotland (🏴󠁧󠁒󠁳󠁣󠁴󠁿) +const emojiRegex = /^(\p{ExtPict}|\p{Emoji}(\p{EMod})?|\p{Emoji}\uFE0F|\p{Emoji}\u20E3|[\u{1F3FB}-\u{1F3FF}]|[\u{1F1E6}-\u{1F1FF}]{2}|\p{Emoji}[\u{E0020}-\u{E007E}]+\u{E007F}|\p{Emoji}(\uFE0F)?(\u200D\p{Emoji}(\uFE0F)?)+)$/u // Helper function to validate emoji export function isValidEmoji (str: string): boolean { diff --git a/test/unit/emoji.spec.ts b/test/unit/emoji.spec.ts new file mode 100644 index 00000000..c1eb3c64 --- /dev/null +++ b/test/unit/emoji.spec.ts @@ -0,0 +1,49 @@ +import { describe, expect, it } from 'vitest' +import { isValidEmoji } from '../../shared/utils/emoji' + +describe('emoji validation', () => { + it('validates basic emoji correctly', () => { + // Basic emoji should pass + expect(isValidEmoji('πŸ˜€')).toBe(true) + expect(isValidEmoji('πŸ‘')).toBe(true) + expect(isValidEmoji('❀️')).toBe(true) + + // Non-emoji should fail + expect(isValidEmoji('abc')).toBe(false) + expect(isValidEmoji('')).toBe(false) + expect(isValidEmoji(' ')).toBe(false) + }) + + it('validates emoji with modifiers correctly', () => { + // Emoji with skin tone modifiers + expect(isValidEmoji('πŸ‘πŸ»')).toBe(true) + expect(isValidEmoji('πŸ‘πŸ½')).toBe(true) + expect(isValidEmoji('πŸ‘πŸΏ')).toBe(true) + }) + + it('validates complex emoji correctly', () => { + // ZWJ sequences (family, couples, etc.) + expect(isValidEmoji('πŸ‘¨β€πŸ‘©β€πŸ‘§')).toBe(true) + expect(isValidEmoji('πŸ‘©β€πŸ’»')).toBe(true) + + // Flag emoji + expect(isValidEmoji('πŸ‡ΊπŸ‡Έ')).toBe(true) + expect(isValidEmoji('πŸ‡―πŸ‡΅')).toBe(true) + + // Regional flags like Scotland flag + expect(isValidEmoji('🏴󠁧󠁒󠁳󠁣󠁴󠁿')).toBe(true) + }) + + it('rejects multiple emoji', () => { + // Multiple emoji should fail + expect(isValidEmoji('πŸ˜€πŸ˜€')).toBe(false) + expect(isValidEmoji('πŸ‘β€οΈ')).toBe(false) + expect(isValidEmoji('πŸ‘¨β€πŸ‘©β€πŸ‘§πŸ‘¨β€πŸ‘©β€πŸ‘§')).toBe(false) + }) + + it('rejects emoji with additional text', () => { + expect(isValidEmoji('πŸ˜€abc')).toBe(false) + expect(isValidEmoji('abcπŸ˜€')).toBe(false) + expect(isValidEmoji(' πŸ˜€ ')).toBe(false) + }) +})