1717import { vi , describe , it , expect , beforeEach } from 'vitest' ;
1818import { DEBUG , INFO , WARN , ERROR , LogLevel } from '@optimizely/optimizely-sdk' ;
1919import type { LoggerConfig , LogHandler } from '@optimizely/optimizely-sdk' ;
20+ import { storeLoggerConfig , getLoggerConfig } from './loggerConfigRegistry' ;
21+ import { createReactLogger } from './ReactLogger' ;
22+ import type { ReactLoggerConfig } from './ReactLogger' ;
2023
2124const mockOpaqueLogger = vi . hoisted ( ( ) => ( { __opaque : true } ) ) ;
2225
@@ -28,7 +31,7 @@ vi.mock('@optimizely/optimizely-sdk', async (importOriginal) => {
2831 } ;
2932} ) ;
3033
31- import { createLogger , getReactLogger } from './createLogger' ;
34+ import { createLogger } from './createLogger' ;
3235
3336describe ( 'createLogger' , ( ) => {
3437 beforeEach ( ( ) => {
@@ -41,24 +44,62 @@ describe('createLogger', () => {
4144 expect ( result ) . toBe ( mockOpaqueLogger ) ;
4245 } ) ;
4346
44- it ( 'should make the ReactLogger available via getReactLogger' , ( ) => {
45- const config : LoggerConfig = { level : INFO } ;
46- createLogger ( config ) ;
47-
48- const reactLogger = getReactLogger ( ) ;
49- expect ( reactLogger ) . toBeDefined ( ) ;
50- expect ( typeof reactLogger ! . debug ) . toBe ( 'function' ) ;
51- expect ( typeof reactLogger ! . info ) . toBe ( 'function' ) ;
52- expect ( typeof reactLogger ! . warn ) . toBe ( 'function' ) ;
53- expect ( typeof reactLogger ! . error ) . toBe ( 'function' ) ;
47+ it ( 'should store the resolved config in the registry' , ( ) => {
48+ const mockHandler : LogHandler = { log : vi . fn ( ) } ;
49+ createLogger ( { level : INFO , logHandler : mockHandler } ) ;
50+
51+ const storedConfig = getLoggerConfig ( mockOpaqueLogger ) ;
52+ expect ( storedConfig ) . toBeDefined ( ) ;
53+ expect ( storedConfig ! . logLevel ) . toBe ( LogLevel . Info ) ;
54+ expect ( storedConfig ! . logHandler ) . toBe ( mockHandler ) ;
55+ } ) ;
56+
57+ describe ( 'log level resolution' , ( ) => {
58+ it . each ( [
59+ { preset : DEBUG , expected : LogLevel . Debug , name : 'DEBUG' } ,
60+ { preset : INFO , expected : LogLevel . Info , name : 'INFO' } ,
61+ { preset : WARN , expected : LogLevel . Warn , name : 'WARN' } ,
62+ { preset : ERROR , expected : LogLevel . Error , name : 'ERROR' } ,
63+ ] ) ( 'should resolve $name preset to LogLevel.$name' , ( { preset, expected } ) => {
64+ createLogger ( { level : preset } ) ;
65+ const storedConfig = getLoggerConfig ( mockOpaqueLogger ) ;
66+ expect ( storedConfig ! . logLevel ) . toBe ( expected ) ;
67+ } ) ;
5468 } ) ;
69+ } ) ;
70+
71+ describe ( 'loggerConfigRegistry' , ( ) => {
72+ it ( 'should return undefined for unknown logger objects' , ( ) => {
73+ expect ( getLoggerConfig ( { } ) ) . toBeUndefined ( ) ;
74+ } ) ;
75+
76+ it ( 'should store and retrieve config for a given logger' , ( ) => {
77+ const logger = { } ;
78+ const config : ReactLoggerConfig = { logLevel : LogLevel . Warn } ;
79+ storeLoggerConfig ( logger , config ) ;
80+ expect ( getLoggerConfig ( logger ) ) . toBe ( config ) ;
81+ } ) ;
82+
83+ it ( 'should support multiple loggers with different configs' , ( ) => {
84+ const logger1 = { } ;
85+ const logger2 = { } ;
86+ const config1 : ReactLoggerConfig = { logLevel : LogLevel . Debug } ;
87+ const config2 : ReactLoggerConfig = { logLevel : LogLevel . Error } ;
5588
89+ storeLoggerConfig ( logger1 , config1 ) ;
90+ storeLoggerConfig ( logger2 , config2 ) ;
91+
92+ expect ( getLoggerConfig ( logger1 ) ) . toBe ( config1 ) ;
93+ expect ( getLoggerConfig ( logger2 ) ) . toBe ( config2 ) ;
94+ } ) ;
95+ } ) ;
96+
97+ describe ( 'createReactLogger' , ( ) => {
5698 describe ( 'log level filtering' , ( ) => {
5799 it ( 'should filter messages below the configured level' , ( ) => {
58100 const mockHandler : LogHandler = { log : vi . fn ( ) } ;
59- createLogger ( { level : WARN , logHandler : mockHandler } ) ;
101+ const logger = createReactLogger ( { logLevel : LogLevel . Warn , logHandler : mockHandler } ) ;
60102
61- const logger = getReactLogger ( ) ! ;
62103 logger . debug ( 'should not appear' ) ;
63104 logger . info ( 'should not appear' ) ;
64105 logger . warn ( 'should appear' ) ;
@@ -69,11 +110,10 @@ describe('createLogger', () => {
69110 expect ( mockHandler . log ) . toHaveBeenCalledWith ( LogLevel . Error , '[ReactSDK] should appear' ) ;
70111 } ) ;
71112
72- it ( 'should allow all messages when level is DEBUG ' , ( ) => {
113+ it ( 'should allow all messages when level is Debug ' , ( ) => {
73114 const mockHandler : LogHandler = { log : vi . fn ( ) } ;
74- createLogger ( { level : DEBUG , logHandler : mockHandler } ) ;
115+ const logger = createReactLogger ( { logLevel : LogLevel . Debug , logHandler : mockHandler } ) ;
75116
76- const logger = getReactLogger ( ) ! ;
77117 logger . debug ( 'd' ) ;
78118 logger . info ( 'i' ) ;
79119 logger . warn ( 'w' ) ;
@@ -82,11 +122,10 @@ describe('createLogger', () => {
82122 expect ( mockHandler . log ) . toHaveBeenCalledTimes ( 4 ) ;
83123 } ) ;
84124
85- it ( 'should only allow error messages when level is ERROR ' , ( ) => {
125+ it ( 'should only allow error messages when level is Error ' , ( ) => {
86126 const mockHandler : LogHandler = { log : vi . fn ( ) } ;
87- createLogger ( { level : ERROR , logHandler : mockHandler } ) ;
127+ const logger = createReactLogger ( { logLevel : LogLevel . Error , logHandler : mockHandler } ) ;
88128
89- const logger = getReactLogger ( ) ! ;
90129 logger . debug ( 'd' ) ;
91130 logger . info ( 'i' ) ;
92131 logger . warn ( 'w' ) ;
@@ -97,26 +136,40 @@ describe('createLogger', () => {
97136 } ) ;
98137 } ) ;
99138
100- describe ( 'custom log handler' , ( ) => {
139+ describe ( 'log handler' , ( ) => {
101140 it ( 'should use the provided logHandler' , ( ) => {
102141 const mockHandler : LogHandler = { log : vi . fn ( ) } ;
103- createLogger ( { level : INFO , logHandler : mockHandler } ) ;
142+ const logger = createReactLogger ( { logLevel : LogLevel . Info , logHandler : mockHandler } ) ;
104143
105- const logger = getReactLogger ( ) ! ;
106144 logger . info ( 'hello' ) ;
107145
108146 expect ( mockHandler . log ) . toHaveBeenCalledWith ( LogLevel . Info , '[ReactSDK] hello' ) ;
109147 } ) ;
110148
111149 it ( 'should use default console handler when logHandler is not provided' , ( ) => {
112150 const consoleSpy = vi . spyOn ( console , 'info' ) . mockImplementation ( ( ) => { } ) ;
113- createLogger ( { level : INFO } ) ;
151+ const logger = createReactLogger ( { logLevel : LogLevel . Info } ) ;
114152
115- const logger = getReactLogger ( ) ! ;
116153 logger . info ( 'hello' ) ;
117154
118155 expect ( consoleSpy ) . toHaveBeenCalledWith ( '[ReactSDK] hello' ) ;
119156 consoleSpy . mockRestore ( ) ;
120157 } ) ;
121158 } ) ;
159+
160+ describe ( 'message prefix' , ( ) => {
161+ it ( 'should prepend [ReactSDK] to all messages' , ( ) => {
162+ const mockHandler : LogHandler = { log : vi . fn ( ) } ;
163+ const logger = createReactLogger ( { logLevel : LogLevel . Debug , logHandler : mockHandler } ) ;
164+
165+ logger . debug ( 'test' ) ;
166+ logger . info ( 'test' ) ;
167+ logger . warn ( 'test' ) ;
168+ logger . error ( 'test' ) ;
169+
170+ for ( const call of ( mockHandler . log as ReturnType < typeof vi . fn > ) . mock . calls ) {
171+ expect ( call [ 1 ] ) . toMatch ( / ^ \[ R e a c t S D K \] / ) ;
172+ }
173+ } ) ;
174+ } ) ;
122175} ) ;
0 commit comments