import { afterEach, beforeEach, describe, expect, mock, it } from 'bun:test' const originalConsoleLog = console.log const mockWithKakaoClient = mock(async (_options: unknown, fn: (client: unknown) => Promise) => { return fn(mockClient) }) const mockGetChats = mock(() => Promise.resolve([ { chat_id: 'chat-1', name: 'General', type: 'group', member_count: 5 }, { chat_id: 'chat-2', name: 'Direct', type: 'direct', member_count: 2 }, ]), ) const mockLeaveChat = mock(() => Promise.resolve({ success: true, status_code: 0, chat_id: 'chat-1' })) const mockClient = { getChats: mockGetChats, leaveChat: mockLeaveChat, } mock.module('./shared', () => ({ withKakaoClient: mockWithKakaoClient, })) import { chatCommand } from './chat' describe('chat commands', () => { let consoleLogSpy: ReturnType beforeEach(() => { mockWithKakaoClient.mockReset() mockGetChats.mockReset() mockLeaveChat.mockReset() mockWithKakaoClient.mockImplementation(async (_options: unknown, fn: (client: unknown) => Promise) => { return fn(mockClient) }) mockGetChats.mockImplementation(() => Promise.resolve([ { chat_id: 'chat-1', name: 'General', type: 'group', member_count: 5 }, { chat_id: 'chat-2', name: 'Direct', type: 'direct', member_count: 2 }, ]), ) mockLeaveChat.mockImplementation(() => Promise.resolve({ success: true, status_code: 0, chat_id: 'chat-1' })) consoleLogSpy = mock((..._args: unknown[]) => {}) console.log = consoleLogSpy }) afterEach(() => { console.log = originalConsoleLog }) describe('list', () => { it('lists chat rooms', async () => { await chatCommand.parseAsync(['list'], { from: 'user' }) expect(mockGetChats).toHaveBeenCalled() const output = JSON.parse(consoleLogSpy.mock.calls[0][0]) expect(output).toHaveLength(2) expect(output[0].chat_id).toBe('chat-1') expect(output[0].name).toBe('General') }) it('passes --search option to getChats', async () => { await chatCommand.parseAsync(['list', '--search', 'General'], { from: 'user' }) const call = mockGetChats.mock.calls[0][0] as { all?: boolean; search?: string } expect(call.search).toBe('General') }) it('passes --all flag to getChats', async () => { await chatCommand.parseAsync(['list', '--all'], { from: 'user' }) const call = mockGetChats.mock.calls[0][0] as { all?: boolean; search?: string } expect(call.all).toBe(true) }) it('passes account option to withKakaoClient', async () => { await chatCommand.parseAsync(['list', '--account', 'my-account'], { from: 'user' }) expect(mockWithKakaoClient).toHaveBeenCalledWith( expect.objectContaining({ account: 'my-account' }), expect.any(Function), ) }) it('outputs empty array when no chats', async () => { mockGetChats.mockImplementation(() => Promise.resolve([])) await chatCommand.parseAsync(['list'], { from: 'user' }) const output = JSON.parse(consoleLogSpy.mock.calls[0][0]) expect(output).toEqual([]) }) }) describe('leave', () => { it('leaves a chat room', async () => { await chatCommand.parseAsync(['leave', 'chat-1'], { from: 'user' }) expect(mockLeaveChat).toHaveBeenCalledWith('chat-1') const output = JSON.parse(consoleLogSpy.mock.calls[0][0]) expect(output).toEqual({ success: true, status_code: 0, chat_id: 'chat-1' }) }) it('passes account option to withKakaoClient', async () => { await chatCommand.parseAsync(['leave', 'chat-1', '--account', 'my-account'], { from: 'user' }) expect(mockWithKakaoClient).toHaveBeenCalledWith( expect.objectContaining({ account: 'my-account' }), expect.any(Function), ) }) }) })