UNPKG

puter-cli

Version:

Command line interface for Puter cloud platform

185 lines (152 loc) 5.63 kB
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { execCommand, getPrompt } from '../src/executor.js'; import { getProfileModule } from '../src/modules/ProfileModule.js'; import readline from 'node:readline'; vi.mock('../src/executor.js'); vi.mock('../src/modules/ProfileModule.js'); vi.mock('node:readline'); vi.mock('conf', () => { const Conf = vi.fn(() => ({ get: vi.fn(), set: vi.fn(), })); return { default: Conf }; }); vi.spyOn(console, 'log').mockImplementation(() => { }); vi.spyOn(console, 'error').mockImplementation(() => { }); let updatePrompt; let startShell; beforeEach(async () => { vi.resetModules(); vi.clearAllMocks(); vi.mocked(getPrompt).mockReturnValue('puter@/> '); vi.mocked(getProfileModule).mockReturnValue({ checkLogin: vi.fn(), }); const mockOn = vi.fn().mockReturnThis(); vi.mocked(readline.createInterface).mockReturnValue({ setPrompt: vi.fn(), prompt: vi.fn(), on: mockOn, }); const module = await import('../src/commands/shell.js'); updatePrompt = module.updatePrompt; startShell = module.startShell; }); describe('updatePrompt', () => { it('should call rl.setPrompt with getPrompt result', async () => { await startShell(); const rl = readline.createInterface.mock.results[0].value; rl.setPrompt.mockClear(); updatePrompt('/test/path'); expect(rl.setPrompt).toHaveBeenCalledWith('puter@/> '); }); }); describe('startShell', () => { it('should call checkLogin', async () => { await startShell(); expect(getProfileModule().checkLogin).toHaveBeenCalled(); }); describe('with command argument', () => { let mockExit; beforeEach(() => { mockExit = vi.spyOn(process, 'exit').mockImplementation(() => { throw new Error('process.exit called'); }); }); afterEach(() => { mockExit.mockRestore(); }); it('should execute command and exit when command is provided', async () => { await expect(startShell('help')).rejects.toThrow('process.exit called'); expect(execCommand).toHaveBeenCalledWith('help'); expect(mockExit).toHaveBeenCalledWith(0); }); it('should not create readline interface when command is provided', async () => { vi.mocked(readline.createInterface).mockClear(); await expect(startShell('help')).rejects.toThrow('process.exit called'); expect(readline.createInterface).not.toHaveBeenCalled(); }); }); describe('without command argument (interactive mode)', () => { it('should create readline interface', async () => { await startShell(); expect(readline.createInterface).toHaveBeenCalledWith({ input: process.stdin, output: process.stdout, prompt: null, }); }); it('should display welcome message', async () => { await startShell(); expect(console.log).toHaveBeenCalledWith(expect.stringContaining('Welcome to Puter-CLI')); }); it('should set prompt and call prompt()', async () => { await startShell(); const rl = readline.createInterface.mock.results[0].value; expect(rl.setPrompt).toHaveBeenCalledWith('puter@/> '); expect(rl.prompt).toHaveBeenCalled(); }); it('should register line and close event handlers', async () => { await startShell(); const rl = readline.createInterface.mock.results[0].value; expect(rl.on).toHaveBeenCalledWith('line', expect.any(Function)); expect(rl.on).toHaveBeenCalledWith('close', expect.any(Function)); }); }); describe('line event handler', () => { let lineHandler; let rl; beforeEach(async () => { await startShell(); rl = readline.createInterface.mock.results[0].value; lineHandler = rl.on.mock.calls.find(call => call[0] === 'line')[1]; }); it('should execute trimmed command', async () => { await lineHandler(' ls '); expect(execCommand).toHaveBeenCalledWith('ls'); }); it('should not execute empty line', async () => { vi.mocked(execCommand).mockClear(); await lineHandler(' '); expect(execCommand).not.toHaveBeenCalled(); }); it('should call prompt after executing command', async () => { rl.prompt.mockClear(); await lineHandler('ls'); expect(rl.prompt).toHaveBeenCalled(); }); it('should log error message when execCommand throws', async () => { vi.mocked(execCommand).mockRejectedValueOnce(new Error('Command failed')); await lineHandler('badcmd'); expect(console.error).toHaveBeenCalledWith(expect.stringContaining('Command failed')); }); it('should still call prompt after error', async () => { vi.mocked(execCommand).mockRejectedValueOnce(new Error('Command failed')); rl.prompt.mockClear(); await lineHandler('badcmd'); expect(rl.prompt).toHaveBeenCalled(); }); }); describe('close event handler', () => { let closeHandler; let mockExit; beforeEach(async () => { mockExit = vi.spyOn(process, 'exit').mockImplementation(() => { }); await startShell(); const rl = readline.createInterface.mock.results[0].value; closeHandler = rl.on.mock.calls.find(call => call[0] === 'close')[1]; }); afterEach(() => { mockExit.mockRestore(); }); it('should display goodbye message', () => { closeHandler(); expect(console.log).toHaveBeenCalledWith(expect.stringContaining('Goodbye')); }); it('should exit with code 0', () => { closeHandler(); expect(mockExit).toHaveBeenCalledWith(0); }); }); });