1+ // Mock Obsidian's prepareFuzzySearch
2+ const mockPrepareFuzzySearch = jest . fn ( ( query : string ) => {
3+ return ( target : string ) => {
4+ // Simple mock implementation for testing
5+ return target . toLowerCase ( ) . includes ( query . toLowerCase ( ) ) ;
6+ } ;
7+ } ) ;
8+
9+ // Mock translations
10+ const mockT = jest . fn ( ( key : string ) => key ) ;
11+
12+ jest . mock ( "obsidian" , ( ) => ( {
13+ prepareFuzzySearch : mockPrepareFuzzySearch
14+ } ) ) ;
15+
16+ jest . mock ( "../translations/helper" , ( ) => ( {
17+ t : mockT
18+ } ) ) ;
19+
20+ import { SettingsIndexer } from "../components/settings/SettingsIndexer" ;
21+ import { SETTINGS_METADATA } from "../data/settings-metadata" ;
22+
23+ describe ( "Settings Search Tests" , ( ) => {
24+ let indexer : SettingsIndexer ;
25+
26+ beforeEach ( ( ) => {
27+ indexer = new SettingsIndexer ( ) ;
28+ jest . clearAllMocks ( ) ;
29+ } ) ;
30+
31+ describe ( "Settings Metadata" , ( ) => {
32+ test ( "should have valid metadata structure" , ( ) => {
33+ expect ( SETTINGS_METADATA ) . toBeDefined ( ) ;
34+ expect ( Array . isArray ( SETTINGS_METADATA ) ) . toBe ( true ) ;
35+ expect ( SETTINGS_METADATA . length ) . toBeGreaterThan ( 0 ) ;
36+
37+ // Check first few items have required fields
38+ const firstItem = SETTINGS_METADATA [ 0 ] ;
39+ expect ( firstItem ) . toHaveProperty ( "id" ) ;
40+ expect ( firstItem ) . toHaveProperty ( "tabId" ) ;
41+ expect ( firstItem ) . toHaveProperty ( "name" ) ;
42+ expect ( firstItem ) . toHaveProperty ( "translationKey" ) ;
43+ expect ( firstItem ) . toHaveProperty ( "keywords" ) ;
44+ expect ( Array . isArray ( firstItem . keywords ) ) . toBe ( true ) ;
45+ } ) ;
46+
47+ test ( "should have progress bar settings" , ( ) => {
48+ const progressBarMain = SETTINGS_METADATA . find ( item => item . id === "progress-bar-main" ) ;
49+ expect ( progressBarMain ) . toBeDefined ( ) ;
50+ expect ( progressBarMain ?. name ) . toBe ( "Progress bar" ) ;
51+ expect ( progressBarMain ?. tabId ) . toBe ( "progress-bar" ) ;
52+ expect ( progressBarMain ?. keywords ) . toContain ( "progress" ) ;
53+ } ) ;
54+
55+ test ( "should have enable task filter setting" , ( ) => {
56+ const taskFilter = SETTINGS_METADATA . find ( item => item . id === "enable-task-filter" ) ;
57+ expect ( taskFilter ) . toBeDefined ( ) ;
58+ expect ( taskFilter ?. name ) . toBe ( "Enable Task Filter" ) ;
59+ expect ( taskFilter ?. tabId ) . toBe ( "task-filter" ) ;
60+ } ) ;
61+ } ) ;
62+
63+ describe ( "SettingsIndexer" , ( ) => {
64+ test ( "should initialize correctly" , ( ) => {
65+ expect ( indexer ) . toBeDefined ( ) ;
66+
67+ // Should not be initialized yet
68+ const stats = indexer . getStats ( ) ;
69+ expect ( stats . itemCount ) . toBeGreaterThan ( 0 ) ;
70+ } ) ;
71+
72+ test ( "should build index on first search" , ( ) => {
73+ const results = indexer . search ( "progress" ) ;
74+ expect ( mockT ) . toHaveBeenCalled ( ) ;
75+ } ) ;
76+
77+ test ( "should search by name" , ( ) => {
78+ const results = indexer . search ( "progress" ) ;
79+
80+ console . log ( "Search results for 'progress':" , results . length ) ;
81+ results . forEach ( result => {
82+ console . log ( `- ${ result . item . name } (${ result . matchType } , score: ${ result . score } )` ) ;
83+ } ) ;
84+
85+ expect ( results . length ) . toBeGreaterThan ( 0 ) ;
86+
87+ // Should find progress bar settings
88+ const progressResult = results . find ( result =>
89+ result . item . id === "progress-bar-main" ||
90+ result . item . name . toLowerCase ( ) . includes ( "progress" )
91+ ) ;
92+ expect ( progressResult ) . toBeDefined ( ) ;
93+ } ) ;
94+
95+ test ( "should search by description" , ( ) => {
96+ const results = indexer . search ( "toggle" ) ;
97+
98+ console . log ( "Search results for 'toggle':" , results . length ) ;
99+ results . forEach ( result => {
100+ console . log ( `- ${ result . item . name } (${ result . matchType } , score: ${ result . score } )` ) ;
101+ if ( result . item . description ) {
102+ console . log ( ` Description: ${ result . item . description . substring ( 0 , 100 ) } ...` ) ;
103+ }
104+ } ) ;
105+
106+ expect ( results . length ) . toBeGreaterThan ( 0 ) ;
107+ } ) ;
108+
109+ test ( "should search by keywords" , ( ) => {
110+ const results = indexer . search ( "checkbox" ) ;
111+
112+ console . log ( "Search results for 'checkbox':" , results . length ) ;
113+ results . forEach ( result => {
114+ console . log ( `- ${ result . item . name } (${ result . matchType } , score: ${ result . score } )` ) ;
115+ console . log ( ` Keywords: ${ result . item . keywords . join ( ", " ) } ` ) ;
116+ } ) ;
117+
118+ expect ( results . length ) . toBeGreaterThan ( 0 ) ;
119+ } ) ;
120+
121+ test ( "should prioritize name matches over description matches" , ( ) => {
122+ const results = indexer . search ( "filter" ) ;
123+
124+ console . log ( "Search results for 'filter' with scores:" ) ;
125+ results . forEach ( result => {
126+ console . log ( `- ${ result . item . name } (${ result . matchType } , score: ${ result . score } )` ) ;
127+ } ) ;
128+
129+ expect ( results . length ) . toBeGreaterThan ( 0 ) ;
130+
131+ // Find name matches and description matches
132+ const nameMatches = results . filter ( r => r . matchType === "name" ) ;
133+ const descriptionMatches = results . filter ( r => r . matchType === "description" ) ;
134+
135+ if ( nameMatches . length > 0 && descriptionMatches . length > 0 ) {
136+ // Name matches should have higher scores
137+ const highestNameScore = Math . max ( ...nameMatches . map ( r => r . score ) ) ;
138+ const highestDescScore = Math . max ( ...descriptionMatches . map ( r => r . score ) ) ;
139+ expect ( highestNameScore ) . toBeGreaterThan ( highestDescScore ) ;
140+ }
141+ } ) ;
142+
143+ test ( "should return empty results for empty query" , ( ) => {
144+ const results = indexer . search ( "" ) ;
145+ expect ( results . length ) . toBe ( 0 ) ;
146+ } ) ;
147+
148+ test ( "should return empty results for very short query" , ( ) => {
149+ const results = indexer . search ( "a" ) ;
150+ expect ( results . length ) . toBe ( 0 ) ;
151+ } ) ;
152+
153+ test ( "should return results for 2+ character query" , ( ) => {
154+ const results = indexer . search ( "pr" ) ;
155+ expect ( results . length ) . toBeGreaterThan ( 0 ) ;
156+ } ) ;
157+
158+ test ( "should limit results" , ( ) => {
159+ const results = indexer . search ( "task" ) ;
160+ console . log ( `Found ${ results . length } results for 'task'` ) ;
161+ expect ( results . length ) . toBeLessThanOrEqual ( 10 ) ; // Default limit
162+ } ) ;
163+
164+ test ( "should handle case insensitive search" , ( ) => {
165+ const lowerResults = indexer . search ( "progress" ) ;
166+ const upperResults = indexer . search ( "PROGRESS" ) ;
167+ const mixedResults = indexer . search ( "Progress" ) ;
168+
169+ expect ( lowerResults . length ) . toBe ( upperResults . length ) ;
170+ expect ( lowerResults . length ) . toBe ( mixedResults . length ) ;
171+ } ) ;
172+ } ) ;
173+
174+ describe ( "Translation Integration" , ( ) => {
175+ test ( "should call translation function for setting names" , ( ) => {
176+ indexer . search ( "progress" ) ;
177+
178+ // Should have called t() for translating setting names
179+ expect ( mockT ) . toHaveBeenCalled ( ) ;
180+
181+ // Check if it was called with expected translation keys
182+ const calls = mockT . mock . calls . map ( ( call : any ) => call [ 0 ] ) ;
183+ console . log ( "Translation calls:" , calls . slice ( 0 , 10 ) ) ; // Show first 10 calls
184+
185+ expect ( calls ) . toContain ( "Progress bar" ) ;
186+ } ) ;
187+ } ) ;
188+
189+ describe ( "Edge Cases" , ( ) => {
190+ test ( "should handle special characters in search" , ( ) => {
191+ const results = indexer . search ( "task-filter" ) ;
192+ expect ( results . length ) . toBeGreaterThanOrEqual ( 0 ) ;
193+ } ) ;
194+
195+ test ( "should handle unicode characters" , ( ) => {
196+ const results = indexer . search ( "设置" ) ;
197+ expect ( results . length ) . toBeGreaterThanOrEqual ( 0 ) ;
198+ } ) ;
199+
200+ test ( "should handle numbers in search" , ( ) => {
201+ const results = indexer . search ( "100" ) ;
202+ expect ( results . length ) . toBeGreaterThanOrEqual ( 0 ) ;
203+ } ) ;
204+ } ) ;
205+
206+ describe ( "Performance" , ( ) => {
207+ test ( "should build index quickly" , ( ) => {
208+ const start = performance . now ( ) ;
209+ indexer . initialize ( ) ;
210+ const end = performance . now ( ) ;
211+
212+ const buildTime = end - start ;
213+ console . log ( `Index build time: ${ buildTime . toFixed ( 2 ) } ms` ) ;
214+ expect ( buildTime ) . toBeLessThan ( 50 ) ; // Should be under 50ms
215+ } ) ;
216+
217+ test ( "should search quickly" , ( ) => {
218+ indexer . initialize ( ) ; // Pre-initialize
219+
220+ const start = performance . now ( ) ;
221+ const results = indexer . search ( "progress" ) ;
222+ const end = performance . now ( ) ;
223+
224+ const searchTime = end - start ;
225+ console . log ( `Search time: ${ searchTime . toFixed ( 2 ) } ms for ${ results . length } results` ) ;
226+ expect ( searchTime ) . toBeLessThan ( 10 ) ; // Should be under 10ms
227+ } ) ;
228+ } ) ;
229+
230+ describe ( "Specific Setting Tests" , ( ) => {
231+ test ( "should find 'Enable Task Filter' setting" , ( ) => {
232+ const results = indexer . search ( "enable task filter" ) ;
233+
234+ console . log ( "Searching for 'enable task filter':" ) ;
235+ results . forEach ( result => {
236+ console . log ( `- ${ result . item . name } (ID: ${ result . item . id } )` ) ;
237+ } ) ;
238+
239+ const exactMatch = results . find ( r => r . item . id === "enable-task-filter" ) ;
240+ expect ( exactMatch ) . toBeDefined ( ) ;
241+ } ) ;
242+
243+ test ( "should find progress bar settings" , ( ) => {
244+ const results = indexer . search ( "progress bar" ) ;
245+
246+ console . log ( "Searching for 'progress bar':" ) ;
247+ results . forEach ( result => {
248+ console . log ( `- ${ result . item . name } (ID: ${ result . item . id } )` ) ;
249+ } ) ;
250+
251+ const progressBarMain = results . find ( r => r . item . id === "progress-bar-main" ) ;
252+ expect ( progressBarMain ) . toBeDefined ( ) ;
253+ expect ( progressBarMain ?. matchType ) . toBe ( "name" ) ;
254+ } ) ;
255+
256+ test ( "should find settings by partial name" , ( ) => {
257+ const results = indexer . search ( "workflow" ) ;
258+
259+ console . log ( "Searching for 'workflow':" ) ;
260+ results . forEach ( result => {
261+ console . log ( `- ${ result . item . name } (ID: ${ result . item . id } )` ) ;
262+ } ) ;
263+
264+ expect ( results . length ) . toBeGreaterThan ( 0 ) ;
265+
266+ // Should find workflow-related settings
267+ const workflowSettings = results . filter ( r =>
268+ r . item . name . toLowerCase ( ) . includes ( "workflow" ) ||
269+ r . item . tabId === "workflow"
270+ ) ;
271+ expect ( workflowSettings . length ) . toBeGreaterThan ( 0 ) ;
272+ } ) ;
273+ } ) ;
274+ } ) ;
0 commit comments