diff --git a/src/lib/utils/highlightText.test.ts b/src/lib/utils/highlightText.test.ts
new file mode 100644
index 0000000..50eaf93
--- /dev/null
+++ b/src/lib/utils/highlightText.test.ts
@@ -0,0 +1,149 @@
+import { describe, it, expect } from 'vitest';
+import { highlightText } from './highlightText';
+
+describe('highlightText', () => {
+ describe('basic behavior', () => {
+ it('returns original text when no search term', () => {
+ expect(highlightText('Hello world', '')).toBe('Hello world');
+ });
+
+ it('returns original text when search term is too short (< 2 chars)', () => {
+ expect(highlightText('Hello world', 'H')).toBe('Hello world');
+ });
+
+ it('returns empty string for empty input', () => {
+ expect(highlightText('', 'search')).toBe('');
+ });
+
+ it('returns escaped empty string for empty input with empty query', () => {
+ expect(highlightText('', '')).toBe('');
+ });
+ });
+
+ describe('highlighting matches', () => {
+ it('highlights single match with mark tag', () => {
+ const result = highlightText('Hello world', 'world');
+ expect(result).toBe('Hello world');
+ });
+
+ it('highlights multiple matches', () => {
+ const result = highlightText('test one test two test', 'test');
+ expect(result).toBe(
+ 'test one test two test'
+ );
+ });
+
+ it('highlights match at beginning', () => {
+ const result = highlightText('start of text', 'start');
+ expect(result).toBe('start of text');
+ });
+
+ it('highlights match at end', () => {
+ const result = highlightText('text at end', 'end');
+ expect(result).toBe('text at end');
+ });
+ });
+
+ describe('case sensitivity', () => {
+ it('matches case-insensitively', () => {
+ const result = highlightText('Hello World', 'hello');
+ expect(result).toBe('Hello World');
+ });
+
+ it('preserves original case in highlighted text', () => {
+ const result = highlightText('HELLO hello Hello', 'hello');
+ expect(result).toBe(
+ 'HELLO hello Hello'
+ );
+ });
+
+ it('matches uppercase query against lowercase text', () => {
+ const result = highlightText('lowercase text', 'LOWER');
+ expect(result).toBe('lowercase text');
+ });
+ });
+
+ describe('special characters', () => {
+ it('handles special regex characters in search term', () => {
+ const result = highlightText('test (parentheses) here', '(parentheses)');
+ expect(result).toBe(
+ 'test (parentheses) here'
+ );
+ });
+
+ it('handles dots in search term', () => {
+ const result = highlightText('file.txt and file.js', 'file.');
+ expect(result).toBe(
+ 'file.txt and file.js'
+ );
+ });
+
+ it('handles asterisks in search term', () => {
+ const result = highlightText('a * b * c', '* b');
+ expect(result).toBe('a * b * c');
+ });
+
+ it('handles brackets in search term', () => {
+ const result = highlightText('array[0] = value', '[0]');
+ expect(result).toBe('array[0] = value');
+ });
+
+ it('handles backslashes in search term', () => {
+ const result = highlightText('path\\to\\file', '\\to');
+ expect(result).toBe('path\\to\\file');
+ });
+ });
+
+ describe('HTML escaping (XSS prevention)', () => {
+ it('escapes HTML tags in original text', () => {
+ const result = highlightText('', 'script');
+ expect(result).toContain('<');
+ expect(result).toContain('>');
+ expect(result).not.toContain('