import { tap, expect } from '@git.zone/tstest/tapbundle'; import * as smartrx from '@push.rocks/smartrx'; import * as smartcli from '../ts/index.js'; class TestWritable implements smartcli.ISmartcliWritable { public chunks: string[] = []; public isTTY: boolean; public columns = 80; constructor(isTTYArg: boolean) { this.isTTY = isTTYArg; } public write(chunkArg: string): boolean { this.chunks.push(chunkArg); return true; } public toString(): string { return this.chunks.join(''); } } tap.test('should create a new Smartcli', async () => { const smartCliTestObject = new smartcli.Smartcli(); expect(smartCliTestObject).toBeInstanceOf(smartcli.Smartcli); }); tap.test('should add an command', async (toolsArg) => { const done = toolsArg.defer(); const smartCliTestObject = new smartcli.Smartcli(); const awesomeCommandSubject = smartCliTestObject.addCommand('awesome'); expect(awesomeCommandSubject).toBeInstanceOf(smartrx.rxjs.Subject); awesomeCommandSubject.subscribe(() => { done.resolve(); }); smartCliTestObject.startParse(['node', 'test.js', 'awesome']); await done.promise; }); tap.test('should start parsing a standardTask', async () => { const smartCliTestObject = new smartcli.Smartcli(); expect(smartCliTestObject.standardCommand()).toBeInstanceOf(smartrx.rxjs.Subject); }); let hasExecuted: boolean = false; tap.test('should accept a command', async () => { const smartCliTestObject = new smartcli.Smartcli(); smartCliTestObject.addCommand('triggerme').subscribe(() => { hasExecuted = true; }); smartCliTestObject.triggerCommand('triggerme', {}); expect(hasExecuted).toBeTrue(); }); tap.test('should render terminal tasks in non-interactive mode', async () => { const stream = new TestWritable(false); const terminal = new smartcli.SmartcliTerminal({ stream, interactive: false, colors: false }); const task = terminal.createTask({ job: 'build package', rows: 2 }); task.update('running tsbuild'); task.complete('done'); const output = stream.toString(); expect(output).toInclude('[start] build package'); expect(output).toInclude('[build package] running tsbuild'); expect(output).toInclude('[ok] build package - done'); expect(terminal.getTasks()).toHaveLength(0); }); tap.test('should render fixed rows in interactive mode', async () => { const stream = new TestWritable(true); const terminal = new smartcli.SmartcliTerminal({ stream, interactive: true, colors: false }); const task = terminal.createTask({ job: 'install dependencies', rows: 2 }); task.update('fetching packages'); const renderedRows = task.renderPlainRows(80); expect(renderedRows).toHaveLength(2); expect(renderedRows[0]).toInclude('[run] install dependencies'); expect(stream.toString()).toInclude('\u001B[2K'); task.complete('installed'); expect(stream.toString()).toInclude('[ok] install dependencies - installed'); expect(terminal.getTasks()).toHaveLength(0); }); tap.test('should attach persistent terminal task errors', async () => { const stream = new TestWritable(true); const terminal = new smartcli.SmartcliTerminal({ stream, interactive: true, colors: false }); const task = terminal.createTask({ job: 'deploy release', rows: 3 }); task.attachError('deployment failed', { keepOpen: true }); expect(task.status).toEqual('failed'); expect(task.getErrorLines()).toContain('deployment failed'); expect(task.renderPlainRows(80)[0]).toInclude('[err] deploy release'); expect(terminal.getTasks()).toHaveLength(1); terminal.clear(); }); tap.test('should collapse failed terminal tasks into permanent output', async () => { const stream = new TestWritable(false); const terminal = new smartcli.SmartcliTerminal({ stream, interactive: false, colors: false }); const task = terminal.createTask({ job: 'publish package' }); task.attachError('registry rejected package'); const output = stream.toString(); expect(output).toInclude('[err] publish package - registry rejected package'); expect(terminal.getTasks()).toHaveLength(0); }); export default tap.start();