@@ -4,6 +4,7 @@ import { ProxyAgent } from "proxy-agent";
44import { describe , it , expect , vi , beforeAll } from "vitest" ;
55import { Inbox } from "./inbox" ;
66import { Storage } from "./storage" ;
7+ import { createMockOutputChannelWithLogger } from "./test-helpers" ;
78
89// Mock dependencies
910vi . mock ( "ws" ) ;
@@ -161,4 +162,178 @@ describe("inbox", () => {
161162) ;
162163expect ( mockWebSocket . close ) . toHaveBeenCalled ( ) ;
163164} ) ;
165+
166+ describe ( "Logger integration" , ( ) => {
167+ it ( "should log messages through Logger when Storage has Logger set" , async ( ) => {
168+ const { logger} = createMockOutputChannelWithLogger ( ) ;
169+
170+ // Mock WebSocket
171+ let openHandler :( ( ) => void ) | undefined ;
172+ const mockWebSocket = {
173+ on :vi . fn ( ( event , handler ) => {
174+ if ( event === "open" ) {
175+ openHandler = handler ;
176+ }
177+ } ) ,
178+ close :vi . fn ( ) ,
179+ } ;
180+ const { WebSocket :MockWebSocket } = await import ( "ws" ) ;
181+ vi . mocked ( MockWebSocket ) . mockImplementation ( ( ) => mockWebSocket as never ) ;
182+
183+ const mockWorkspace = { id :"workspace-123" } as Workspace ;
184+ const mockHttpAgent = { } as ProxyAgent ;
185+ const mockRestClient = {
186+ getAxiosInstance :vi . fn ( ( ) => ( {
187+ defaults :{
188+ baseURL :"https://test.com" ,
189+ headers :{
190+ common :{ } ,
191+ } ,
192+ } ,
193+ } ) ) ,
194+ } as unknown as Api ;
195+
196+ // Create mock Storage that uses Logger
197+ const mockStorage = {
198+ writeToCoderOutputChannel :vi . fn ( ( msg :string ) => {
199+ logger . info ( msg ) ;
200+ } ) ,
201+ } as unknown as Storage ;
202+
203+ new Inbox ( mockWorkspace , mockHttpAgent , mockRestClient , mockStorage ) ;
204+
205+ // Trigger open event
206+ openHandler ?.( ) ;
207+
208+ // Verify "Listening to Coder Inbox" was logged
209+ expect ( mockStorage . writeToCoderOutputChannel ) . toHaveBeenCalledWith (
210+ "Listening to Coder Inbox" ,
211+ ) ;
212+
213+ const logs = logger . getLogs ( ) ;
214+ expect ( logs . length ) . toBe ( 1 ) ;
215+ expect ( logs [ 0 ] . message ) . toBe ( "Listening to Coder Inbox" ) ;
216+ expect ( logs [ 0 ] . level ) . toBe ( "INFO" ) ;
217+ } ) ;
218+
219+ it ( "should log dispose message through Logger" , async ( ) => {
220+ const { logger} = createMockOutputChannelWithLogger ( ) ;
221+
222+ // Mock WebSocket
223+ const mockWebSocket = {
224+ on :vi . fn ( ) ,
225+ close :vi . fn ( ) ,
226+ } ;
227+ const { WebSocket :MockWebSocket } = await import ( "ws" ) ;
228+ vi . mocked ( MockWebSocket ) . mockImplementation ( ( ) => mockWebSocket as never ) ;
229+
230+ const mockWorkspace = { id :"workspace-123" } as Workspace ;
231+ const mockHttpAgent = { } as ProxyAgent ;
232+ const mockRestClient = {
233+ getAxiosInstance :vi . fn ( ( ) => ( {
234+ defaults :{
235+ baseURL :"https://test.com" ,
236+ headers :{
237+ common :{ } ,
238+ } ,
239+ } ,
240+ } ) ) ,
241+ } as unknown as Api ;
242+
243+ // Create mock Storage that uses Logger
244+ const mockStorage = {
245+ writeToCoderOutputChannel :vi . fn ( ( msg :string ) => {
246+ logger . info ( msg ) ;
247+ } ) ,
248+ } as unknown as Storage ;
249+
250+ const inbox = new Inbox (
251+ mockWorkspace ,
252+ mockHttpAgent ,
253+ mockRestClient ,
254+ mockStorage ,
255+ ) ;
256+
257+ // Clear any logs from initialization
258+ logger . clear ( ) ;
259+ vi . mocked ( mockStorage . writeToCoderOutputChannel ) . mockClear ( ) ;
260+
261+ // Dispose
262+ inbox . dispose ( ) ;
263+
264+ // Verify dispose message was logged
265+ expect ( mockStorage . writeToCoderOutputChannel ) . toHaveBeenCalledWith (
266+ "No longer listening to Coder Inbox" ,
267+ ) ;
268+
269+ const logs = logger . getLogs ( ) ;
270+ expect ( logs . length ) . toBe ( 1 ) ;
271+ expect ( logs [ 0 ] . message ) . toBe ( "No longer listening to Coder Inbox" ) ;
272+ } ) ;
273+
274+ it ( "should log error messages through Logger" , async ( ) => {
275+ const { logger} = createMockOutputChannelWithLogger ( ) ;
276+
277+ // Mock WebSocket
278+ let errorHandler :( ( error :Error ) => void ) | undefined ;
279+ const mockWebSocket = {
280+ on :vi . fn ( ( event , handler ) => {
281+ if ( event === "error" ) {
282+ errorHandler = handler ;
283+ }
284+ } ) ,
285+ close :vi . fn ( ) ,
286+ } ;
287+ const { WebSocket :MockWebSocket } = await import ( "ws" ) ;
288+ vi . mocked ( MockWebSocket ) . mockImplementation ( ( ) => mockWebSocket as never ) ;
289+
290+ // Mock errToStr
291+ const { errToStr} = await import ( "./api-helper" ) ;
292+ vi . mocked ( errToStr ) . mockReturnValue ( "WebSocket connection error" ) ;
293+
294+ const mockWorkspace = { id :"workspace-123" } as Workspace ;
295+ const mockHttpAgent = { } as ProxyAgent ;
296+ const mockRestClient = {
297+ getAxiosInstance :vi . fn ( ( ) => ( {
298+ defaults :{
299+ baseURL :"https://test.com" ,
300+ headers :{
301+ common :{ } ,
302+ } ,
303+ } ,
304+ } ) ) ,
305+ } as unknown as Api ;
306+
307+ // Create mock Storage that uses Logger
308+ const mockStorage = {
309+ writeToCoderOutputChannel :vi . fn ( ( msg :string ) => {
310+ logger . info ( msg ) ;
311+ } ) ,
312+ } as unknown as Storage ;
313+
314+ new Inbox ( mockWorkspace , mockHttpAgent , mockRestClient , mockStorage ) ;
315+
316+ // Clear any logs from initialization
317+ logger . clear ( ) ;
318+ vi . mocked ( mockStorage . writeToCoderOutputChannel ) . mockClear ( ) ;
319+
320+ // Trigger error event
321+ const testError = new Error ( "Test WebSocket error" ) ;
322+ errorHandler ?.( testError ) ;
323+
324+ // Verify error was logged
325+ expect ( mockStorage . writeToCoderOutputChannel ) . toHaveBeenCalledWith (
326+ "WebSocket connection error" ,
327+ ) ;
328+
329+ // The second call should be for "No longer listening to Coder Inbox"
330+ // because the error handler calls dispose()
331+ expect ( mockStorage . writeToCoderOutputChannel ) . toHaveBeenCalledTimes ( 2 ) ;
332+
333+ const logs = logger . getLogs ( ) ;
334+ expect ( logs . length ) . toBe ( 2 ) ;
335+ expect ( logs [ 0 ] . message ) . toBe ( "WebSocket connection error" ) ;
336+ expect ( logs [ 1 ] . message ) . toBe ( "No longer listening to Coder Inbox" ) ;
337+ } ) ;
338+ } ) ;
164339} ) ;