1
0
Fork 0

Allow to specify command with builder pattern

pull/1562/head
Nikolai Laevskii 2023-10-12 07:30:25 +02:00
parent b45c9d3801
commit 1581d81aba
3 changed files with 94 additions and 34 deletions

View File

@ -36,6 +36,66 @@ describe('command-runner', () => {
) )
}) })
it('throws error if command is not specified', async () => {
const command = createCommandRunner()
await expect(command.run()).rejects.toThrow('Command was not specified')
})
it('will have exec error if it occured', async () => {
execSpy.mockImplementation(async () => {
throw new Error('test')
})
const command = createCommandRunner('echo', ['hello', 'world'], {
silent: true
})
const context = await command.run()
expect(context.execerr).toBeDefined()
expect(context.execerr?.message).toBe('test')
})
it('allows to set command, args and options', async () => {
execSpy.mockImplementation(async () => 0)
createCommandRunner()
.setCommand('echo')
.setArgs(['hello', 'world'])
.setOptions({silent: true})
.run()
expect(execSpy).toHaveBeenCalledTimes(1)
expect(execSpy).toHaveBeenCalledWith(
'echo',
['hello', 'world'],
expect.objectContaining({
silent: true,
ignoreReturnCode: true
})
)
})
it('allows to modify command, args and options', async () => {
execSpy.mockImplementation(async () => 0)
createCommandRunner('echo', ['hello', 'world'], {silent: true})
.setCommand(commandLine => `${commandLine} hello world`)
.setArgs(() => [])
.setOptions(options => ({...options, env: {test: 'test'}}))
.run()
expect(execSpy).toHaveBeenCalledTimes(1)
expect(execSpy).toHaveBeenCalledWith(
'echo hello world',
[],
expect.objectContaining({
silent: true,
ignoreReturnCode: true,
env: {test: 'test'}
})
)
})
const createExecMock = (output: { const createExecMock = (output: {
stdout: string stdout: string
stderr: string stderr: string
@ -139,37 +199,6 @@ describe('command-runner', () => {
expect(middleware).toHaveBeenCalledTimes(1) expect(middleware).toHaveBeenCalledTimes(1)
}) })
it('runs a middleware on multiple events', async () => {
execSpy.mockImplementation(
createExecMock({stdout: 'foo', stderr: '', exitCode: 1})
)
/* execSpy.mockImplementation(
createExecMock({stdout: '', stderr: '', exitCode: 1})
)
const middleware = jest.fn()
const command = createCommandRunner('echo', ['hello', 'world'], {
silent: true
}).on(['!no-stdout', 'ok'], middleware)
await command.run()
expect(middleware).toHaveBeenCalledTimes(1)
execSpy.mockImplementation(async () => {
return {
stdout: '',
stderr: '',
exitCode: 1
}
})
await command.run()
expect(middleware).toHaveBeenCalledTimes(1)
*/
})
}) })
}) })
}) })

View File

@ -137,7 +137,7 @@ export class CommandRunner extends CommandRunnerBase {
} }
export const createCommandRunner = ( export const createCommandRunner = (
commandLine: string, commandLine = '',
args: string[] = [], args: string[] = [],
options: CommandRunnerOptions = {} options: CommandRunnerOptions = {}
): CommandRunner => new CommandRunner(commandLine, args, options, exec.exec) ): CommandRunner => new CommandRunner(commandLine, args, options, exec.exec)

View File

@ -11,12 +11,39 @@ export class CommandRunnerBase {
private middleware: PromisifiedFn<CommandRunnerMiddleware>[] = [] private middleware: PromisifiedFn<CommandRunnerMiddleware>[] = []
constructor( constructor(
private commandLine: string, private commandLine = '',
private args: string[] = [], private args: string[] = [],
private options: CommandRunnerOptions, private options: CommandRunnerOptions,
private executor: typeof exec.exec = exec.exec private executor: typeof exec.exec = exec.exec
) {} ) {}
setCommand(commandLine: string | ((commandLine: string) => string)): this {
this.commandLine =
typeof commandLine === 'function'
? commandLine(this.commandLine)
: commandLine
return this
}
setArgs(args: string[] | ((args: string[]) => string[])): this {
this.args =
typeof args === 'function' ? args(this.args) : [...this.args, ...args]
return this
}
setOptions(
options:
| CommandRunnerOptions
| ((options: CommandRunnerOptions) => CommandRunnerOptions)
): this {
this.options =
typeof options === 'function' ? options(this.options) : options
return this
}
use(middleware: CommandRunnerMiddleware): this { use(middleware: CommandRunnerMiddleware): this {
this.middleware.push(promisifyFn(middleware)) this.middleware.push(promisifyFn(middleware))
return this return this
@ -47,6 +74,10 @@ export class CommandRunnerBase {
exitCode: null exitCode: null
} }
if (!context.commandLine) {
throw new Error('Command was not specified')
}
try { try {
const stderrDecoder = new StringDecoder('utf8') const stderrDecoder = new StringDecoder('utf8')
const stdErrListener = (data: Buffer): void => { const stdErrListener = (data: Buffer): void => {
@ -84,7 +115,7 @@ export class CommandRunnerBase {
} }
export function composeMiddleware( export function composeMiddleware(
middleware: PromisifiedFn<CommandRunnerMiddleware>[] middleware: CommandRunnerMiddleware[]
): PromisifiedFn<CommandRunnerMiddleware> { ): PromisifiedFn<CommandRunnerMiddleware> {
middleware = middleware.map(mw => promisifyFn(mw)) middleware = middleware.map(mw => promisifyFn(mw))