@@ -3,21 +3,37 @@ import { createSessionScanner } from './sessionScanner'
33import { RawJSONLines } from '../types'
44import { mkdir , writeFile , appendFile , rm , readFile } from 'node:fs/promises'
55import { join } from 'node:path'
6- import { tmpdir , homedir } from 'node:os'
6+ import { tmpdir } from 'node:os'
77import { existsSync } from 'node:fs'
8+ import { getProjectPath } from './path'
9+
10+ async function waitFor ( predicate : ( ) => boolean , timeoutMs : number = 2000 , intervalMs : number = 25 ) : Promise < void > {
11+ const start = Date . now ( )
12+ while ( Date . now ( ) - start < timeoutMs ) {
13+ if ( predicate ( ) ) return
14+ await new Promise ( resolve => setTimeout ( resolve , intervalMs ) )
15+ }
16+ throw new Error ( 'Timed out waiting for condition' )
17+ }
818
919describe ( 'sessionScanner' , ( ) => {
1020 let testDir : string
1121 let projectDir : string
1222 let collectedMessages : RawJSONLines [ ]
1323 let scanner : Awaited < ReturnType < typeof createSessionScanner > > | null = null
24+ let originalClaudeConfigDir : string | undefined
25+ let claudeConfigDir : string
1426
1527 beforeEach ( async ( ) => {
1628 testDir = join ( tmpdir ( ) , `scanner-test-${ Date . now ( ) } ` )
1729 await mkdir ( testDir , { recursive : true } )
1830
19- const projectName = testDir . replace ( / \/ / g, '-' )
20- projectDir = join ( homedir ( ) , '.claude' , 'projects' , projectName )
31+ // Ensure the scanner and this test agree on where session files live.
32+ // (getProjectPath uses CLAUDE_CONFIG_DIR + a sanitized project id derived from workingDirectory.)
33+ originalClaudeConfigDir = process . env . CLAUDE_CONFIG_DIR ;
34+ claudeConfigDir = join ( testDir , 'claude-config' ) ;
35+ process . env . CLAUDE_CONFIG_DIR = claudeConfigDir ;
36+ projectDir = getProjectPath ( testDir ) ;
2137 await mkdir ( projectDir , { recursive : true } )
2238
2339 collectedMessages = [ ]
@@ -30,6 +46,12 @@ describe('sessionScanner', () => {
3046 scanner = null
3147 }
3248
49+ if ( originalClaudeConfigDir === undefined ) {
50+ delete process . env . CLAUDE_CONFIG_DIR ;
51+ } else {
52+ process . env . CLAUDE_CONFIG_DIR = originalClaudeConfigDir ;
53+ }
54+
3355 if ( existsSync ( testDir ) ) {
3456 await rm ( testDir , { recursive : true , force : true } )
3557 }
@@ -60,7 +82,7 @@ describe('sessionScanner', () => {
6082 // Write first line
6183 await writeFile ( sessionFile1 , lines1 [ 0 ] + '\n' )
6284 scanner . onNewSession ( sessionId1 )
63- await new Promise ( resolve => setTimeout ( resolve , 100 ) )
85+ await waitFor ( ( ) => collectedMessages . length >= 1 )
6486
6587 expect ( collectedMessages ) . toHaveLength ( 1 )
6688 expect ( collectedMessages [ 0 ] . type ) . toBe ( 'user' )
@@ -73,7 +95,7 @@ describe('sessionScanner', () => {
7395 // Write second line with delay
7496 await new Promise ( resolve => setTimeout ( resolve , 50 ) )
7597 await appendFile ( sessionFile1 , lines1 [ 1 ] + '\n' )
76- await new Promise ( resolve => setTimeout ( resolve , 200 ) )
98+ await waitFor ( ( ) => collectedMessages . length >= 2 )
7799
78100 expect ( collectedMessages ) . toHaveLength ( 2 )
79101 expect ( collectedMessages [ 1 ] . type ) . toBe ( 'assistant' )
@@ -99,7 +121,7 @@ describe('sessionScanner', () => {
99121 await writeFile ( sessionFile2 , initialContent )
100122
101123 scanner . onNewSession ( sessionId2 )
102- await new Promise ( resolve => setTimeout ( resolve , 100 ) )
124+ await waitFor ( ( ) => collectedMessages . length >= phase1Count + 1 )
103125
104126 // Should have added only 1 new message (summary)
105127 // The historical user + assistant messages (lines 1-2) are deduplicated because they have same UUIDs
@@ -109,7 +131,7 @@ describe('sessionScanner', () => {
109131 // Write new messages (user asks for ls tool) - this is line 3
110132 await new Promise ( resolve => setTimeout ( resolve , 50 ) )
111133 await appendFile ( sessionFile2 , lines2 [ 3 ] + '\n' )
112- await new Promise ( resolve => setTimeout ( resolve , 200 ) )
134+ await waitFor ( ( ) => collectedMessages . some ( m => m . type === 'user' && m . message . content === 'run ls tool ' ) )
113135
114136 // Find the user message we just added
115137 const userMessages = collectedMessages . filter ( m => m . type === 'user' )
@@ -124,7 +146,12 @@ describe('sessionScanner', () => {
124146 await new Promise ( resolve => setTimeout ( resolve , 50 ) )
125147 await appendFile ( sessionFile2 , lines2 [ i ] + '\n' )
126148 }
127- await new Promise ( resolve => setTimeout ( resolve , 300 ) )
149+ await waitFor ( ( ) => collectedMessages . some ( m =>
150+ m . type === 'assistant' &&
151+ Array . isArray ( ( m . message ?. content as any ) ) &&
152+ typeof ( m . message ?. content as any ) [ 0 ] ?. text === 'string' &&
153+ ( m . message ?. content as any ) [ 0 ] . text . includes ( '0-say-lol-session.jsonl' )
154+ ) , 5000 )
128155
129156 // Final count check
130157 const finalMessages = collectedMessages . slice ( phase1Count )
@@ -204,4 +231,4 @@ describe('sessionScanner', () => {
204231 // expect(lastAssistantMsg.message.id).toBe('msg_01KWeuP88pkzRtXmggJRnQmV')
205232 // }
206233 } )
207- } )
234+ } )
0 commit comments