Files
readest/apps/readest-app/src/__tests__/services/rsvp-utils.test.ts
T
Huang Xin 0e516f6e56 chore(test): add unit tests and enforce dash-case naming for test files (#3715)
Add ~290 new unit tests covering utils (lru, diff, css, a11y, walk,
usage, txt-worker), services (EdgeTTSClient, transformers), and
suppress noisy console output across all test files. Rename 27
camelCase test files to dash-case for consistency.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 09:14:00 +02:00

244 lines
7.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, test, expect } from 'vitest';
import {
isCJK,
containsCJK,
isCJKPunctuation,
getSegmenterLocale,
segmentCJKText,
splitTextIntoWords,
} from '@/services/rsvp/utils';
describe('rsvp/utils', () => {
describe('isCJK', () => {
test('returns true for CJK Unified Ideographs', () => {
expect(isCJK('\u4e00')).toBe(true); // first CJK character
expect(isCJK('\u9fff')).toBe(true); // last CJK character
expect(isCJK('\u5f00')).toBe(true); // 开
});
test('returns true for Hiragana', () => {
expect(isCJK('\u3042')).toBe(true); // あ
});
test('returns true for Katakana', () => {
expect(isCJK('\u30A2')).toBe(true); // ア
});
test('returns true for Hangul', () => {
expect(isCJK('\uAC00')).toBe(true); // 가
});
test('returns true for CJK Extension A', () => {
expect(isCJK('\u3400')).toBe(true);
});
test('returns true for CJK Compatibility Ideographs', () => {
expect(isCJK('\uF900')).toBe(true);
});
test('returns false for Latin characters', () => {
expect(isCJK('a')).toBe(false);
expect(isCJK('Z')).toBe(false);
});
test('returns false for digits', () => {
expect(isCJK('1')).toBe(false);
});
test('returns false for spaces', () => {
expect(isCJK(' ')).toBe(false);
});
});
describe('containsCJK', () => {
test('returns true for text with CJK characters', () => {
expect(containsCJK('Hello 你好')).toBe(true);
});
test('returns true for pure CJK text', () => {
expect(containsCJK('你好世界')).toBe(true);
});
test('returns false for pure Latin text', () => {
expect(containsCJK('Hello World')).toBe(false);
});
test('returns false for empty string', () => {
expect(containsCJK('')).toBe(false);
});
test('returns true for Japanese hiragana', () => {
expect(containsCJK('こんにちは')).toBe(true);
});
test('returns true for Korean', () => {
expect(containsCJK('안녕하세요')).toBe(true);
});
});
describe('isCJKPunctuation', () => {
test('returns true for Chinese period', () => {
expect(isCJKPunctuation('。')).toBe(true);
});
test('returns true for Chinese comma', () => {
expect(isCJKPunctuation('')).toBe(true);
});
test('returns true for full-width exclamation', () => {
expect(isCJKPunctuation('')).toBe(true);
});
test('returns true for full-width question mark', () => {
expect(isCJKPunctuation('')).toBe(true);
});
test('returns true for brackets', () => {
expect(isCJKPunctuation('【')).toBe(true);
expect(isCJKPunctuation('】')).toBe(true);
expect(isCJKPunctuation('「')).toBe(true);
expect(isCJKPunctuation('」')).toBe(true);
});
test('returns true for ellipsis', () => {
expect(isCJKPunctuation('…')).toBe(true);
});
test('returns false for standard Latin comma', () => {
expect(isCJKPunctuation(',')).toBe(false);
});
test('returns false for Latin period', () => {
expect(isCJKPunctuation('.')).toBe(false);
});
test('returns false for a letter', () => {
expect(isCJKPunctuation('A')).toBe(false);
});
});
describe('getSegmenterLocale', () => {
test('returns ja for Japanese hiragana text', () => {
expect(getSegmenterLocale('こんにちは')).toBe('ja');
});
test('returns ja for Katakana text', () => {
expect(getSegmenterLocale('アイウ')).toBe('ja');
});
test('returns ko for Korean text', () => {
expect(getSegmenterLocale('안녕하세요')).toBe('ko');
});
test('returns zh for Chinese text', () => {
expect(getSegmenterLocale('你好世界')).toBe('zh');
});
test('returns null for pure Latin text', () => {
expect(getSegmenterLocale('Hello World')).toBeNull();
});
test('returns null for empty string', () => {
expect(getSegmenterLocale('')).toBeNull();
});
test('detects first CJK script in mixed text', () => {
// Japanese hiragana appears first
expect(getSegmenterLocale('あ你好')).toBe('ja');
});
});
describe('segmentCJKText', () => {
test('segments Chinese text into words', () => {
const words = segmentCJKText('你好世界');
expect(words.length).toBeGreaterThan(0);
expect(words.join('')).toContain('你好');
});
test('segments Japanese text', () => {
const words = segmentCJKText('こんにちは');
expect(words.length).toBeGreaterThan(0);
});
test('handles text with punctuation', () => {
const words = segmentCJKText('你好。世界!');
expect(words.length).toBeGreaterThan(0);
});
test('handles empty text', () => {
const words = segmentCJKText('');
expect(words).toEqual([]);
});
test('handles single character', () => {
const words = segmentCJKText('你');
expect(words.length).toBeGreaterThanOrEqual(1);
});
test('attaches trailing CJK punctuation', () => {
const words = segmentCJKText('你好!');
// The punctuation should be attached to a word
const hasWordWithPunct = words.some((w) => w.includes(''));
expect(hasWordWithPunct).toBe(true);
});
});
describe('splitTextIntoWords', () => {
test('splits English text by spaces', () => {
const words = splitTextIntoWords('Hello World');
expect(words).toEqual(['Hello', 'World']);
});
test('splits multi-word English text', () => {
const words = splitTextIntoWords('The quick brown fox');
expect(words).toEqual(['The', 'quick', 'brown', 'fox']);
});
test('filters empty words', () => {
const words = splitTextIntoWords(' Hello World ');
expect(words.every((w) => w.trim().length > 0)).toBe(true);
});
test('handles CJK text', () => {
const words = splitTextIntoWords('你好世界');
expect(words.length).toBeGreaterThan(0);
});
test('handles mixed CJK and Latin text', () => {
const words = splitTextIntoWords('Hello 你好 World');
expect(words.length).toBeGreaterThan(0);
// Should contain both CJK and Latin segments
});
test('handles empty string', () => {
const words = splitTextIntoWords('');
expect(words).toEqual([]);
});
test('handles CJK text with punctuation', () => {
const words = splitTextIntoWords('你好。世界!');
expect(words.length).toBeGreaterThan(0);
});
test('handles CJK followed immediately by non-CJK', () => {
const words = splitTextIntoWords('你好Hello');
expect(words.length).toBeGreaterThanOrEqual(1);
});
test('handles standalone CJK punctuation at start', () => {
const words = splitTextIntoWords('。Hello');
expect(words.length).toBeGreaterThan(0);
});
test('handles non-CJK text followed by CJK punctuation', () => {
const words = splitTextIntoWords('Hello。');
expect(words.length).toBeGreaterThan(0);
});
test('handles whitespace between CJK segments', () => {
const words = splitTextIntoWords('你好 世界');
expect(words.length).toBeGreaterThan(0);
});
});
});