@@ -8,7 +8,6 @@ import { mkdirSync, rmSync, existsSync, readFileSync } from 'fs';
88import { join } from 'path' ;
99import { randomUUID } from 'crypto' ;
1010import type { Logger } from '../src/logger.js' ;
11- import { getTestFileTimeout } from '../src/logger-validation.js' ;
1211
1312// Store original env
1413const originalEnv = process . env ;
@@ -19,7 +18,9 @@ describe('Logger Output Configuration', () => {
1918 let getLoggerOutputMode : ( ) => string ;
2019 let createChildLogger : ( name : string , context ?: Record < string , unknown > ) => Logger ;
2120
22- const testLogDir = join ( process . cwd ( ) , 'test-logs' ) ;
21+ // Use a unique directory for this test suite run to avoid conflicts
22+ const testRunId = randomUUID ( ) ;
23+ const testLogDir = join ( process . cwd ( ) , 'test-logs' , testRunId ) ;
2324 const testLogFile = join ( testLogDir , 'test.log' ) ;
2425
2526 beforeEach ( ( ) => {
@@ -32,13 +33,37 @@ describe('Logger Output Configuration', () => {
3233 }
3334 } ) ;
3435
35- afterEach ( ( ) => {
36+ afterEach ( async ( ) => {
3637 process . env = originalEnv ;
3738 vi . clearAllMocks ( ) ;
3839
39- // Clean up test log directory
40+ // Add a small delay to let any async file operations complete
41+ await new Promise ( ( resolve ) => setTimeout ( resolve , 10 ) ) ;
42+
43+ // Clean up test log directory with error handling
4044 if ( existsSync ( testLogDir ) ) {
41- rmSync ( testLogDir , { recursive : true , force : true } ) ;
45+ try {
46+ rmSync ( testLogDir , { recursive : true , force : true } ) ;
47+ } catch ( error ) {
48+ // Ignore ENOENT errors as they're expected if the directory was already removed
49+ // Also ignore EBUSY errors from async operations still in progress
50+ if ( error && typeof error === 'object' && 'code' in error ) {
51+ const code = ( error as { code ?: string } ) . code ;
52+ if ( code !== 'ENOENT' && code !== 'EBUSY' ) {
53+ throw error ;
54+ }
55+ }
56+ }
57+ }
58+
59+ // Clean up the parent test-logs directory if it's empty
60+ const parentTestLogDir = join ( process . cwd ( ) , 'test-logs' ) ;
61+ if ( existsSync ( parentTestLogDir ) ) {
62+ try {
63+ rmSync ( parentTestLogDir , { recursive : true , force : true } ) ;
64+ } catch {
65+ // Ignore errors - directory may still have async operations
66+ }
4267 }
4368 } ) ;
4469
@@ -121,17 +146,29 @@ describe('Logger Output Configuration', () => {
121146 process . env . LOG_OUTPUT = 'file' ;
122147 process . env . LOG_FILE_PATH = testLogFile ;
123148 process . env . NODE_ENV = 'development' ;
149+ // Disable file rotation for this test to make it more predictable
150+ delete process . env . LOG_FILE_MAX_SIZE ;
151+ delete process . env . LOG_FILE_MAX_FILES ;
124152
125153 const loggerModule = await import ( '../src/logger.js' ) ;
126154 logger = loggerModule . logger ;
127155
128- // Log multiple messages to ensure file is written
129- logger . info ( 'Test message for file output 1' ) ;
130- logger . info ( 'Test message for file output 2' ) ;
131- logger . info ( 'Test message for file output 3' ) ;
156+ // Log a message
157+ logger . info ( 'Test message for file output' ) ;
132158
133- // Give more time for async file write in CI
134- await new Promise ( ( resolve ) => setTimeout ( resolve , getTestFileTimeout ( ) ) ) ;
159+ // Wait for file to be created with a simple retry mechanism
160+ // This is more reliable than a fixed timeout
161+ let attempts = 0 ;
162+ const maxAttempts = 20 ;
163+ const retryDelay = 50 ;
164+
165+ while ( attempts < maxAttempts ) {
166+ if ( existsSync ( testLogFile ) ) {
167+ break ;
168+ }
169+ await new Promise ( ( resolve ) => setTimeout ( resolve , retryDelay ) ) ;
170+ attempts ++ ;
171+ }
135172
136173 // Check if log file was created
137174 expect ( existsSync ( testLogFile ) ) . toBe ( true ) ;
@@ -173,20 +210,30 @@ describe('Logger Output Configuration', () => {
173210 process . env . LOG_OUTPUT = 'file' ;
174211 process . env . LOG_FILE_PATH = nestedLogPath ;
175212 process . env . NODE_ENV = 'development' ;
213+ // Disable file rotation for predictability
214+ delete process . env . LOG_FILE_MAX_SIZE ;
215+ delete process . env . LOG_FILE_MAX_FILES ;
176216
177217 const loggerModule = await import ( '../src/logger.js' ) ;
178218 logger = loggerModule . logger ;
179219
180- // Log multiple messages to ensure file is created
181- logger . info ( 'Test nested directory creation 1' ) ;
182- logger . info ( 'Test nested directory creation 2' ) ;
183- logger . info ( 'Test nested directory creation 3' ) ;
220+ // Log a message
221+ logger . info ( 'Test nested directory creation' ) ;
184222
185- // Give more time for async file operations in CI
186- await new Promise ( ( resolve ) => setTimeout ( resolve , getTestFileTimeout ( ) ) ) ;
223+ // Wait for directory to be created with retry mechanism
224+ let attempts = 0 ;
225+ const maxAttempts = 20 ;
226+ const retryDelay = 50 ;
227+
228+ while ( attempts < maxAttempts ) {
229+ if ( existsSync ( nestedLogDir ) ) {
230+ break ;
231+ }
232+ await new Promise ( ( resolve ) => setTimeout ( resolve , retryDelay ) ) ;
233+ attempts ++ ;
234+ }
187235
188- // Check if nested directories were created (check directory, not file)
189- // File creation may be delayed, but directory should exist
236+ // Check if nested directories were created
190237 expect ( existsSync ( nestedLogDir ) ) . toBe ( true ) ;
191238 } ) ;
192239 } ) ;
@@ -377,11 +424,8 @@ describe('Logger Output Configuration', () => {
377424 expect ( logger ) . toBeDefined ( ) ;
378425
379426 // Give pino-roll a moment to finish any async operations
380- // Use configurable timeout for CI environments
381- const timeout = process . env . LOG_TEST_FILE_TIMEOUT
382- ? parseInt ( process . env . LOG_TEST_FILE_TIMEOUT , 10 )
383- : 50 ;
384- await new Promise ( ( resolve ) => setTimeout ( resolve , timeout ) ) ;
427+ // Using a small fixed delay since we're just checking config parsing
428+ await new Promise ( ( resolve ) => setTimeout ( resolve , 50 ) ) ;
385429 } finally {
386430 // Clean up the unique directory after each test
387431 // Use a try-catch to handle any cleanup errors gracefully
0 commit comments