first-character.test.ts 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. import firstCharacter from '@/shared/utils/first-character'
  2. import { expect } from 'chai'
  3. import sinon from 'sinon'
  4. const CASES_ALL = [
  5. // Regular ASCII characters
  6. ['Hello', 'H'],
  7. // Multi-byte characters (e.g. Chinese)
  8. ['你好', '你'],
  9. // Multi-byte characters (e.g. emojis)
  10. ['😀 Smile', '😀'],
  11. // Empty string
  12. ['', ''],
  13. ]
  14. const CASES_SEGMENTER = [
  15. // Regional indicator symbols (e.g. flag emojis)
  16. ['🇩🇰 Denmark', '🇩🇰'],
  17. // ZWJ sequences (e.g. family emoji)
  18. ['👩‍👩‍👧‍👦 Family', '👩‍👩‍👧‍👦'],
  19. // Combining characters (e.g. accented characters)
  20. ['e\u0301 Accented', 'e\u0301'],
  21. ['é Accented', 'é'],
  22. ]
  23. describe('firstCharacter', function () {
  24. it('works for different types of strings', function () {
  25. for (const [input, expected] of CASES_ALL) {
  26. expect(firstCharacter(input)).to.equal(expected)
  27. }
  28. for (const [input, expected] of CASES_SEGMENTER) {
  29. expect(firstCharacter(input)).to.equal(expected)
  30. }
  31. })
  32. describe('when Intl.Segmenter is unavailable', function () {
  33. before(function () {
  34. this.segmenterStub = sinon.stub(Intl, 'Segmenter').value(undefined)
  35. })
  36. after(function () {
  37. this.segmenterStub.restore()
  38. })
  39. it('falls back to the code point approach', function () {
  40. for (const [input, expected] of CASES_ALL) {
  41. expect(firstCharacter(input)).to.equal(expected)
  42. }
  43. })
  44. })
  45. })