@@ -39,7 +39,34 @@ describe('LoggerUtils', () => {
3939 delete ( loggerUtils . _globalThis as any ) [ Symbol . for ( 'logger' ) ] ;
4040 } ) ;
4141
42+ it ( 'exports default sensitive fields as a non-empty array' , ( ) => {
43+ expect ( Array . isArray ( loggerUtils . defaultSensitiveFields ) ) . toBe ( true ) ;
44+ expect ( loggerUtils . defaultSensitiveFields . length ) . toBeGreaterThan ( 0 ) ;
45+ expect ( loggerUtils . defaultSensitiveFields ) . toContain ( 'password' ) ;
46+ } ) ;
47+
48+ it ( 'exposes default redact censor and allows replacing/restoring it' , ( ) => {
49+ const original = loggerUtils . getRedactCensor ( ) ;
50+ const replacement = jest . fn ( ) . mockReturnValue ( 'MASKED' ) ;
51+
52+ try {
53+ loggerUtils . setRedactCensor ( replacement ) ;
54+ expect ( loggerUtils . getRedactCensor ( ) ) . toBe ( replacement ) ;
55+ expect ( loggerUtils . redact ( 'value' , [ 'path' ] ) ) . toBe ( 'MASKED' ) ;
56+ } finally {
57+ loggerUtils . setRedactCensor ( original ) ;
58+ }
59+ } ) ;
60+
4261 describe ( 'getLogger' , ( ) => {
62+ it ( 'returns a fresh non-global logger when newInstance is true' , ( ) => {
63+ ( ContextStore . get as jest . Mock ) . mockReturnValue ( undefined ) ;
64+ const logger = loggerUtils . getLogger ( true ) ;
65+
66+ expect ( logger ) . toBe ( mockLogger ) ;
67+ expect ( ( loggerUtils . _globalThis as any ) [ Symbol . for ( 'logger' ) ] ) . toBeUndefined ( ) ;
68+ } ) ;
69+
4370 it ( 'returns logger from context if available' , ( ) => {
4471 ( ContextStore . get as jest . Mock ) . mockReturnValue ( mockLogger ) ;
4572 const logger = loggerUtils . getLogger ( ) ;
@@ -160,6 +187,68 @@ describe('LoggerUtils', () => {
160187 ) ;
161188 expect ( logger ) . toBe ( mockLogger ) ;
162189 } ) ;
190+
191+ it ( 'uses multistream transport when pretty and file logging are enabled' , ( ) => {
192+ const transportMock = jest . fn ( ) . mockReturnValue ( 'transported' ) ;
193+ ( pino as any ) . transport = transportMock ;
194+
195+ setCatbeeGlobalConfig ( {
196+ logger : {
197+ pretty : true ,
198+ dir : 'logs' ,
199+ level : 'info' ,
200+ colorize : true ,
201+ singleLine : true
202+ }
203+ } ) ;
204+
205+ loggerUtils . getLogger ( ) ;
206+
207+ expect ( transportMock ) . toHaveBeenCalledWith (
208+ expect . objectContaining ( {
209+ targets : expect . arrayContaining ( [
210+ expect . objectContaining ( { target : 'pino-pretty' } ) ,
211+ expect . objectContaining ( { target : 'pino/file' } )
212+ ] )
213+ } )
214+ ) ;
215+ } ) ;
216+
217+ it ( 'uses file-only transport when only logger dir is configured' , ( ) => {
218+ const transportMock = jest . fn ( ) . mockReturnValue ( 'transported' ) ;
219+ ( pino as any ) . transport = transportMock ;
220+
221+ setCatbeeGlobalConfig ( {
222+ logger : {
223+ pretty : false ,
224+ dir : 'logs'
225+ }
226+ } ) ;
227+
228+ loggerUtils . getLogger ( ) ;
229+
230+ expect ( transportMock ) . toHaveBeenCalledWith (
231+ expect . objectContaining ( {
232+ target : 'pino/file' ,
233+ options : expect . objectContaining ( { destination : 'logs/app.log' } )
234+ } )
235+ ) ;
236+ } ) ;
237+
238+ it ( 'uses plain pino without transport when pretty and file logging are disabled' , ( ) => {
239+ ( pino as any ) . transport = jest . fn ( ) . mockReturnValue ( 'transported' ) ;
240+ setCatbeeGlobalConfig ( {
241+ logger : {
242+ pretty : false ,
243+ dir : ''
244+ }
245+ } ) ;
246+
247+ loggerUtils . getLogger ( ) ;
248+
249+ expect ( ( pino as any ) . transport ) . not . toHaveBeenCalled ( ) ;
250+ expect ( pino ) . toHaveBeenCalledWith ( expect . objectContaining ( { level : 'info' } ) ) ;
251+ } ) ;
163252 } ) ;
164253
165254 describe ( 'redactCensor' , ( ) => {
@@ -206,6 +295,18 @@ describe('LoggerUtils', () => {
206295 expect ( loggerUtils . getRedactCensor ( ) ( { key : 'value' } as any , [ 'object' ] ) ) . toBe ( '***' ) ;
207296 } ) ;
208297
298+ it ( 'should return original value for non-sensitive custom top-level path' , ( ) => {
299+ expect ( loggerUtils . getRedactCensor ( ) ( 'trace-123' , [ 'meta' , 'traceId' ] ) ) . toBe ( 'trace-123' ) ;
300+ } ) ;
301+
302+ it ( 'should fallback to "***" when authorization value is empty' , ( ) => {
303+ expect ( loggerUtils . getRedactCensor ( ) ( '' , [ 'req' , 'headers' , 'authorization' ] ) ) . toBe ( '***' ) ;
304+ } ) ;
305+
306+ it ( 'should ignore non-string path segments while evaluating redaction' , ( ) => {
307+ expect ( loggerUtils . getRedactCensor ( ) ( 'safe' , [ 'meta' , 123 as unknown as string ] as string [ ] ) ) . toBe ( 'safe' ) ;
308+ } ) ;
309+
209310 describe ( 'setRedactCensor and getRedactCensor' , ( ) => {
210311 it ( 'should allow setting and getting a custom redaction function' , ( ) => {
211312 // Save original censor to restore after test
0 commit comments