From 88d2add1b984b675795104afcefbed0cd0aaadae Mon Sep 17 00:00:00 2001 From: Martin Svoboda Date: Sat, 5 Oct 2024 21:49:51 +0200 Subject: [PATCH 1/4] Correctly pass args array to exec function --- src/client.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/client.ts b/src/client.ts index 11c9f54b..09060828 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1291,7 +1291,7 @@ export class Client { await this.shell(serial, `am force-stop ${pkg}`); } - private execInternal(...args: ReadonlyArray): Promise { + private execInternal(args: ReadonlyArray): Promise { return new Promise((resolve, reject) => { execFile(this.options.bin, args, (err, stdout, stderr) => { if (err) { @@ -1315,24 +1315,27 @@ export class Client { /** * Executes a given command via adb console interface. */ - public exec(cmd: string): Promise { - return this.execInternal(cmd); + public exec(cmd: string | string[]): Promise { + return this.execInternal([cmd].flat()); } /** * Executes a given command on specific device via adb console interface. * Analogous to `adb -s `. */ - public execDevice(serial: string, cmd: string): Promise { - return this.execInternal(...['-s', serial, cmd]); + public execDevice(serial: string, cmd: string | string[]): Promise { + return this.execInternal(['-s', serial].concat(cmd)); } /** * Executes a given command on specific device shell via adb console interface. * Analogous to `adb -s shell ` . */ - public execDeviceShell(serial: string, cmd: string): Promise { - return this.execInternal(...['-s', serial, 'shell', cmd]); + public execDeviceShell( + serial: string, + cmd: string | string[] + ): Promise { + return this.execInternal(['-s', serial, 'shell'].concat(cmd)); } /** From 1d4b49d6a5b2451d0ecda9178f74b1b3858548b0 Mon Sep 17 00:00:00 2001 From: Martin Svoboda Date: Sat, 5 Oct 2024 21:50:08 +0200 Subject: [PATCH 2/4] Rework tests --- __tests__/adbClient/exec.ts | 46 +++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/__tests__/adbClient/exec.ts b/__tests__/adbClient/exec.ts index 53e29bc9..e9a3e27e 100644 --- a/__tests__/adbClient/exec.ts +++ b/__tests__/adbClient/exec.ts @@ -1,17 +1,49 @@ import { Client } from '../../lib/client'; import { AdbExecError } from '../../lib/util'; -import { mockExec } from '../../mockery/execMock'; +import { execFile } from 'child_process'; + +jest.mock('child_process', () => ({ + execFile: jest.fn() +})); + +const mockExecFile = execFile as unknown as jest.Mock; describe('Exec tests', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); it('Should execute without error', async () => { - mockExec(null, '', ''); + let callback; + mockExecFile.mockImplementation((_cmd, _args, callback_) => { + callback = callback_; + callback_(null, '', ''); + }); const adb = new Client({ noAutoStart: true }); const result = await adb.exec('cmd'); expect(result).toBe(''); + expect(mockExecFile).toHaveBeenCalledWith('adb', ['cmd'], callback); + }); + + it('Should execute with multiple parameters', async () => { + let callback; + mockExecFile.mockImplementation((_cmd, _args, callback_) => { + callback = callback_; + callback_(null, '', ''); + }); + const adb = new Client({ noAutoStart: true }); + const result = await adb.exec(['cmd', 'param']); + expect(result).toBe(''); + expect(mockExecFile).toHaveBeenCalledWith( + 'adb', + ['cmd', 'param'], + callback + ); }); it('Should execute with error', async () => { - mockExec(new Error('message'), '', ''); + mockExecFile.mockImplementation((_cmd, _args, callback_) => { + callback_(new Error('message'), '', ''); + }); const adb = new Client({ noAutoStart: true }); await expect(() => adb.exec('cmd')).rejects.toEqual( new Error('message') @@ -19,7 +51,9 @@ describe('Exec tests', () => { }); it('Should execute with std error', async () => { - mockExec(null, '', 'message'); + mockExecFile.mockImplementation((_cmd, _args, callback_) => { + callback_(null, '', 'message'); + }); const adb = new Client({ noAutoStart: true }); try { await adb.exec('cmd'); @@ -31,7 +65,9 @@ describe('Exec tests', () => { }); it('Should execute with std out matching error reg exp', async () => { - mockExec(null, 'Error: message', ''); + mockExecFile.mockImplementation((_cmd, _args, callback_) => { + callback_(null, 'Error: message', ''); + }); const adb = new Client({ noAutoStart: true }); try { await adb.exec('cmd'); From 0df57a0f93f481d7692285210fdbeabe4712ce99 Mon Sep 17 00:00:00 2001 From: Martin Svoboda Date: Sun, 6 Oct 2024 13:41:51 +0200 Subject: [PATCH 3/4] Fix tests, remove mocks --- __tests__/adbClient/connection.ts | 14 +- .../adbClient/constructorAndStartServer.ts | 12 +- __tests__/adbClient/exec.ts | 3 - __tests__/adbClient/execDevice.ts | 47 +++- __tests__/adbClient/execDeviceShell.ts | 47 +++- __tests__/device/exec.ts | 46 +++- __tests__/device/execShell.ts | 46 +++- mockery/execMock.ts | 34 --- mockery/mockChildProcess.ts | 203 ------------------ src/device.ts | 4 +- 10 files changed, 189 insertions(+), 267 deletions(-) delete mode 100644 mockery/execMock.ts delete mode 100644 mockery/mockChildProcess.ts diff --git a/__tests__/adbClient/connection.ts b/__tests__/adbClient/connection.ts index c258adf9..a13ad77f 100644 --- a/__tests__/adbClient/connection.ts +++ b/__tests__/adbClient/connection.ts @@ -1,11 +1,19 @@ import { Client } from '../../lib'; -import { mockExec } from '../../mockery/execMock'; +import { execFile } from 'child_process'; + +jest.mock('child_process', () => ({ + execFile: jest.fn() +})); + +const mockExecFile = execFile as unknown as jest.Mock; describe('Client connection tests', () => { it('Should try to start server on ECONNREFUSED error', async () => { - const mocked = mockExec(null); + mockExecFile.mockImplementation((_cmd, _args, callback_) => { + callback_(null, '', ''); + }); const client = new Client({ port: 1 }); await expect(() => client['connection']()).rejects.toThrow(); - expect(mocked).toHaveBeenCalledTimes(1); + expect(mockExecFile).toHaveBeenCalledTimes(1); }); }); diff --git a/__tests__/adbClient/constructorAndStartServer.ts b/__tests__/adbClient/constructorAndStartServer.ts index d50e71e3..e8140965 100644 --- a/__tests__/adbClient/constructorAndStartServer.ts +++ b/__tests__/adbClient/constructorAndStartServer.ts @@ -1,5 +1,11 @@ import { Client } from '../../lib/client'; -import { mockExec } from '../../mockery/execMock'; +import { execFile } from 'child_process'; + +jest.mock('child_process', () => ({ + execFile: jest.fn() +})); + +const mockExecFile = execFile as unknown as jest.Mock; describe('Client constructor tests', () => { it('Create Adb client instance', () => { @@ -25,7 +31,9 @@ describe('Client constructor tests', () => { describe('Start server tests', () => { it('Start adb server', async () => { - mockExec(null); + mockExecFile.mockImplementation((_cmd, _args, callback_) => { + callback_(null, '', ''); + }); const client = new Client(); await expect(client.startServer()).resolves.toBeUndefined(); }); diff --git a/__tests__/adbClient/exec.ts b/__tests__/adbClient/exec.ts index e9a3e27e..c2decb1f 100644 --- a/__tests__/adbClient/exec.ts +++ b/__tests__/adbClient/exec.ts @@ -9,9 +9,6 @@ jest.mock('child_process', () => ({ const mockExecFile = execFile as unknown as jest.Mock; describe('Exec tests', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); it('Should execute without error', async () => { let callback; mockExecFile.mockImplementation((_cmd, _args, callback_) => { diff --git a/__tests__/adbClient/execDevice.ts b/__tests__/adbClient/execDevice.ts index 0a755a42..46b8aede 100644 --- a/__tests__/adbClient/execDevice.ts +++ b/__tests__/adbClient/execDevice.ts @@ -1,17 +1,50 @@ import { Client } from '../../lib/client'; import { AdbExecError } from '../../lib/util'; -import { mockExec } from '../../mockery/execMock'; +import { execFile } from 'child_process'; + +jest.mock('child_process', () => ({ + execFile: jest.fn() +})); + +const mockExecFile = execFile as unknown as jest.Mock; describe('Exec device tests', () => { it('Should execute without error', async () => { - mockExec(null, '', ''); + let callback; + mockExecFile.mockImplementation((_cmd, _args, callback_) => { + callback = callback_; + callback_(null, '', ''); + }); const adb = new Client({ noAutoStart: true }); const result = await adb.execDevice('serial', 'cmd'); expect(result).toBe(''); + expect(mockExecFile).toHaveBeenCalledWith( + 'adb', + ['-s', 'serial', 'cmd'], + callback + ); + }); + + it('Should execute with multiple parameters', async () => { + let callback; + mockExecFile.mockImplementation((_cmd, _args, callback_) => { + callback = callback_; + callback_(null, '', ''); + }); + const adb = new Client({ noAutoStart: true }); + const result = await adb.execDevice('serial', ['cmd', 'param']); + expect(result).toBe(''); + expect(mockExecFile).toHaveBeenCalledWith( + 'adb', + ['-s', 'serial', 'cmd', 'param'], + callback + ); }); it('Should execute with error', async () => { - mockExec(new Error('message'), '', ''); + mockExecFile.mockImplementation((_cmd, _args, callback_) => { + callback_(new Error('message'), '', ''); + }); const adb = new Client({ noAutoStart: true }); await expect(() => adb.execDevice('serial', 'cmd')).rejects.toEqual( new Error('message') @@ -19,7 +52,9 @@ describe('Exec device tests', () => { }); it('Should execute with std error', async () => { - mockExec(null, '', 'message'); + mockExecFile.mockImplementation((_cmd, _args, callback_) => { + callback_(null, '', 'message'); + }); const adb = new Client({ noAutoStart: true }); try { await adb.execDevice('serial', 'cmd'); @@ -31,7 +66,9 @@ describe('Exec device tests', () => { }); it('Should execute with std out matching error reg exp', async () => { - mockExec(null, 'Error: message', ''); + mockExecFile.mockImplementation((_cmd, _args, callback_) => { + callback_(null, 'Error: message', ''); + }); const adb = new Client({ noAutoStart: true }); try { await adb.execDevice('serial', 'cmd'); diff --git a/__tests__/adbClient/execDeviceShell.ts b/__tests__/adbClient/execDeviceShell.ts index 235a2e4e..0c115177 100644 --- a/__tests__/adbClient/execDeviceShell.ts +++ b/__tests__/adbClient/execDeviceShell.ts @@ -1,17 +1,50 @@ import { Client } from '../../lib/client'; import { AdbExecError } from '../../lib/util'; -import { mockExec } from '../../mockery/execMock'; +import { execFile } from 'child_process'; + +jest.mock('child_process', () => ({ + execFile: jest.fn() +})); + +const mockExecFile = execFile as unknown as jest.Mock; describe('Exec device shell tests', () => { it('Should execute without error', async () => { - mockExec(null, '', ''); + let callback; + mockExecFile.mockImplementation((_cmd, _args, callback_) => { + callback = callback_; + callback_(null, '', ''); + }); const adb = new Client({ noAutoStart: true }); const result = await adb.execDeviceShell('serial', 'cmd'); expect(result).toBe(''); + expect(mockExecFile).toHaveBeenCalledWith( + 'adb', + ['-s', 'serial', 'shell', 'cmd'], + callback + ); + }); + + it('Should execute with multiple params', async () => { + let callback; + mockExecFile.mockImplementation((_cmd, _args, callback_) => { + callback = callback_; + callback_(null, '', ''); + }); + const adb = new Client({ noAutoStart: true }); + const result = await adb.execDeviceShell('serial', ['cmd', 'param']); + expect(result).toBe(''); + expect(mockExecFile).toHaveBeenCalledWith( + 'adb', + ['-s', 'serial', 'shell', 'cmd', 'param'], + callback + ); }); it('Should execute with error', async () => { - mockExec(new Error('message'), '', ''); + mockExecFile.mockImplementation((_cmd, _args, callback_) => { + callback_(new Error('message'), '', ''); + }); const adb = new Client({ noAutoStart: true }); await expect(() => adb.execDeviceShell('serial', 'cmd') @@ -19,7 +52,9 @@ describe('Exec device shell tests', () => { }); it('Should execute with std error', async () => { - mockExec(null, '', 'message'); + mockExecFile.mockImplementation((_cmd, _args, callback_) => { + callback_(null, '', 'message'); + }); const adb = new Client({ noAutoStart: true }); try { await adb.execDeviceShell('serial', 'cmd'); @@ -31,7 +66,9 @@ describe('Exec device shell tests', () => { }); it('Should execute with std out matching error reg exp', async () => { - mockExec(null, 'Error: message', ''); + mockExecFile.mockImplementation((_cmd, _args, callback_) => { + callback_(null, 'Error: message', ''); + }); const adb = new Client({ noAutoStart: true }); try { await adb.execDeviceShell('serial', 'cmd'); diff --git a/__tests__/device/exec.ts b/__tests__/device/exec.ts index c4c29395..0a383cd7 100644 --- a/__tests__/device/exec.ts +++ b/__tests__/device/exec.ts @@ -1,7 +1,13 @@ import { Client } from '../../lib/client'; import { Device } from '../../lib/device'; import { AdbExecError } from '../../lib/util'; -import { mockExec } from '../../mockery/execMock'; +import { execFile } from 'child_process'; + +jest.mock('child_process', () => ({ + execFile: jest.fn() +})); + +const mockExecFile = execFile as unknown as jest.Mock; const device = new Device(new Client({ noAutoStart: true }), { id: 'serial', @@ -16,20 +22,48 @@ const device = new Device(new Client({ noAutoStart: true }), { describe('Device exec tests', () => { it('Should execute without error', async () => { - mockExec(null, '', ''); + let callback; + mockExecFile.mockImplementation((_cmd, _args, callback_) => { + callback = callback_; + callback_(null, '', ''); + }); const result = await device.exec('cmd'); expect(result).toBe(''); + expect(mockExecFile).toHaveBeenCalledWith( + 'adb', + ['-s', 'serial', 'cmd'], + callback + ); + }); + + it('Should execute with multiple params', async () => { + let callback; + mockExecFile.mockImplementation((_cmd, _args, callback_) => { + callback = callback_; + callback_(null, '', ''); + }); + const result = await device.exec(['cmd', 'param']); + expect(result).toBe(''); + expect(mockExecFile).toHaveBeenCalledWith( + 'adb', + ['-s', 'serial', 'cmd', 'param'], + callback + ); }); it('Should execute with error', async () => { - mockExec(new Error('message'), '', ''); + mockExecFile.mockImplementation((_cmd, _args, callback_) => { + callback_(new Error('message'), '', ''); + }); await expect(() => device.exec('cmd')).rejects.toEqual( new Error('message') ); }); it('Should execute with std error', async () => { - mockExec(null, '', 'message'); + mockExecFile.mockImplementation((_cmd, _args, callback_) => { + callback_(null, '', 'message'); + }); try { await device.exec('cmd'); } catch (e: unknown) { @@ -40,7 +74,9 @@ describe('Device exec tests', () => { }); it('Should execute with std out matching error reg exp', async () => { - mockExec(null, 'Error: message', ''); + mockExecFile.mockImplementation((_cmd, _args, callback_) => { + callback_(null, 'Error: message', ''); + }); try { await device.exec('cmd'); } catch (e: unknown) { diff --git a/__tests__/device/execShell.ts b/__tests__/device/execShell.ts index 3e829799..74f60a50 100644 --- a/__tests__/device/execShell.ts +++ b/__tests__/device/execShell.ts @@ -1,7 +1,13 @@ import { Client } from '../../lib/client'; import { Device } from '../../lib/device'; import { AdbExecError } from '../../lib/util'; -import { mockExec } from '../../mockery/execMock'; +import { execFile } from 'child_process'; + +jest.mock('child_process', () => ({ + execFile: jest.fn() +})); + +const mockExecFile = execFile as unknown as jest.Mock; const device = new Device(new Client({ noAutoStart: true }), { id: 'serial', @@ -16,20 +22,48 @@ const device = new Device(new Client({ noAutoStart: true }), { describe('Device exec shell tests', () => { it('Should execute shell command without error', async () => { - mockExec(null, '', ''); + let callback; + mockExecFile.mockImplementation((_cmd, _args, callback_) => { + callback = callback_; + callback_(null, '', ''); + }); const result = await device.execShell('cmd'); expect(result).toBe(''); + expect(mockExecFile).toHaveBeenCalledWith( + 'adb', + ['-s', 'serial', 'shell', 'cmd'], + callback + ); + }); + + it('Should execute shell command with multiple parameters', async () => { + let callback; + mockExecFile.mockImplementation((_cmd, _args, callback_) => { + callback = callback_; + callback_(null, '', ''); + }); + const result = await device.execShell(['cmd', 'param']); + expect(result).toBe(''); + expect(mockExecFile).toHaveBeenCalledWith( + 'adb', + ['-s', 'serial', 'shell', 'cmd', 'param'], + callback + ); }); it('Should execute shell command with error', async () => { - mockExec(new Error('message'), '', ''); + mockExecFile.mockImplementation((_cmd, _args, callback_) => { + callback_(new Error('message'), '', ''); + }); await expect(() => device.execShell('cmd')).rejects.toEqual( new Error('message') ); }); it('Should execute shell command with std error', async () => { - mockExec(null, '', 'message'); + mockExecFile.mockImplementation((_cmd, _args, callback_) => { + callback_(null, '', 'message'); + }); try { await device.execShell('cmd'); } catch (e: unknown) { @@ -40,7 +74,9 @@ describe('Device exec shell tests', () => { }); it('Should execute shell command with std out matching error reg exp', async () => { - mockExec(null, 'Error: message', ''); + mockExecFile.mockImplementation((_cmd, _args, callback_) => { + callback_(null, 'Error: message', ''); + }); try { await device.execShell('cmd'); } catch (e: unknown) { diff --git a/mockery/execMock.ts b/mockery/execMock.ts deleted file mode 100644 index a5c058b3..00000000 --- a/mockery/execMock.ts +++ /dev/null @@ -1,34 +0,0 @@ -import ChildProcess from 'child_process'; -import { EncodingOption } from 'fs'; -import { ChildProcessMock } from './mockChildProcess'; - -export const mockExec = ( - err: ChildProcess.ExecException | null, - stdout = '', - stderr = '' -): jest.SpyInstance => { - return jest - .spyOn(ChildProcess, 'execFile') - .mockImplementation( - ( - _file: string, - _args: ReadonlyArray | undefined | null, - cb: - | ( - | (EncodingOption & ChildProcess.ExecFileOptions) - | undefined - | null - ) - | (( - error: ChildProcess.ExecException | null, - stdout: string, - stderr: string - ) => void) - ) => { - if (typeof cb === 'function') { - cb(err, stdout, stderr); - } - return new ChildProcessMock(); - } - ); -}; diff --git a/mockery/mockChildProcess.ts b/mockery/mockChildProcess.ts deleted file mode 100644 index 3c926d34..00000000 --- a/mockery/mockChildProcess.ts +++ /dev/null @@ -1,203 +0,0 @@ -/* eslint-disable @typescript-eslint/explicit-member-accessibility */ -import { - MessageOptions, - SendHandle, - Serializable, - ChildProcess -} from 'child_process'; -import { Pipe, Readable, Writable } from 'stream'; - -export class ChildProcessMock implements ChildProcess { - stdin!: Writable | null; - stdout!: Readable | null; - stderr!: Readable | null; - channel?: Pipe | null | undefined; - stdio!: [ - Writable | null, - Readable | null, - Readable | null, - Writable | Readable | null | undefined, - Writable | Readable | null | undefined - ]; - killed!: boolean; - pid!: number; - connected!: boolean; - exitCode!: number | null; - signalCode!: NodeJS.Signals | null; - spawnargs!: string[]; - spawnfile!: string; - kill(): boolean { - throw new Error('Method not implemented.'); - } - send( - message: Serializable, - callback?: ((error: Error | null) => void) | undefined - ): boolean; - send( - message: Serializable, - sendHandle?: SendHandle | undefined, - callback?: ((error: Error | null) => void) | undefined - ): boolean; - send( - message: Serializable, - sendHandle?: SendHandle | undefined, - options?: MessageOptions | undefined, - callback?: ((error: Error | null) => void) | undefined - ): boolean; - send(): boolean { - throw new Error('Method not implemented.'); - } - disconnect(): void { - throw new Error('Method not implemented.'); - } - unref(): void { - throw new Error('Method not implemented.'); - } - ref(): void { - throw new Error('Method not implemented.'); - } - addListener(event: string, listener: (...args: unknown[]) => void): this; - addListener( - event: 'close', - listener: (code: number | null, signal: NodeJS.Signals | null) => void - ): this; - addListener(event: 'disconnect', listener: () => void): this; - addListener(event: 'error', listener: (err: Error) => void): this; - addListener( - event: 'exit', - listener: (code: number | null, signal: NodeJS.Signals | null) => void - ): this; - addListener( - event: 'message', - listener: (message: Serializable, sendHandle: SendHandle) => void - ): this; - addListener(): this { - throw new Error('Method not implemented.'); - } - emit(): boolean; - emit( - event: 'close', - code: number | null, - signal: NodeJS.Signals | null - ): boolean; - emit(event: 'disconnect'): boolean; - emit(event: 'error', err: Error): boolean; - emit( - event: 'exit', - code: number | null, - signal: NodeJS.Signals | null - ): boolean; - emit( - event: 'message', - message: Serializable, - sendHandle: SendHandle - ): boolean; - emit(): boolean { - throw new Error('Method not implemented.'); - } - on(event: string, listener: (...args: unknown[]) => void): this; - on( - event: 'close', - listener: (code: number | null, signal: NodeJS.Signals | null) => void - ): this; - on(event: 'disconnect', listener: () => void): this; - on(event: 'error', listener: (err: Error) => void): this; - on( - event: 'exit', - listener: (code: number | null, signal: NodeJS.Signals | null) => void - ): this; - on( - event: 'message', - listener: (message: Serializable, sendHandle: SendHandle) => void - ): this; - on(): this { - throw new Error('Method not implemented.'); - } - once(event: string, listener: (...args: unknown[]) => void): this; - once( - event: 'close', - listener: (code: number | null, signal: NodeJS.Signals | null) => void - ): this; - once(event: 'disconnect', listener: () => void): this; - once(event: 'error', listener: (err: Error) => void): this; - once( - event: 'exit', - listener: (code: number | null, signal: NodeJS.Signals | null) => void - ): this; - once( - event: 'message', - listener: (message: Serializable, sendHandle: SendHandle) => void - ): this; - once(): this { - throw new Error('Method not implemented.'); - } - prependListener( - event: string, - listener: (...args: unknown[]) => void - ): this; - prependListener( - event: 'close', - listener: (code: number | null, signal: NodeJS.Signals | null) => void - ): this; - prependListener(event: 'disconnect', listener: () => void): this; - prependListener(event: 'error', listener: (err: Error) => void): this; - prependListener( - event: 'exit', - listener: (code: number | null, signal: NodeJS.Signals | null) => void - ): this; - prependListener( - event: 'message', - listener: (message: Serializable, sendHandle: SendHandle) => void - ): this; - prependListener(): this { - throw new Error('Method not implemented.'); - } - prependOnceListener( - event: string, - listener: (...args: unknown[]) => void - ): this; - prependOnceListener( - event: 'close', - listener: (code: number | null, signal: NodeJS.Signals | null) => void - ): this; - prependOnceListener(event: 'disconnect', listener: () => void): this; - prependOnceListener(event: 'error', listener: (err: Error) => void): this; - prependOnceListener( - event: 'exit', - listener: (code: number | null, signal: NodeJS.Signals | null) => void - ): this; - prependOnceListener( - event: 'message', - listener: (message: Serializable, sendHandle: SendHandle) => void - ): this; - prependOnceListener(): this { - throw new Error('Method not implemented.'); - } - removeListener(): this { - throw new Error('Method not implemented.'); - } - off(): this { - throw new Error('Method not implemented.'); - } - removeAllListeners(): this { - throw new Error('Method not implemented.'); - } - setMaxListeners(): this { - throw new Error('Method not implemented.'); - } - getMaxListeners(): number { - throw new Error('Method not implemented.'); - } - listeners(): (() => void)[] { - throw new Error('Method not implemented.'); - } - rawListeners(): (() => void)[] { - throw new Error('Method not implemented.'); - } - listenerCount(): number { - throw new Error('Method not implemented.'); - } - eventNames(): (string | symbol)[] { - throw new Error('Method not implemented.'); - } -} diff --git a/src/device.ts b/src/device.ts index a2d12fc5..f40979e0 100644 --- a/src/device.ts +++ b/src/device.ts @@ -342,11 +342,11 @@ export class Device implements IDevice { return this.client.killApp(this.id, pkg); } - public exec(cmd: string): Promise { + public exec(cmd: string | string[]): Promise { return this.client.execDevice(this.id, cmd); } - public execShell(cmd: string): Promise { + public execShell(cmd: string | string[]): Promise { return this.client.execDeviceShell(this.id, cmd); } From 9c8cef89de153b824337c2a48ede4befe8b422c9 Mon Sep 17 00:00:00 2001 From: Martin Svoboda Date: Thu, 10 Oct 2024 16:28:55 +0200 Subject: [PATCH 4/4] Add documentation --- README_DOCS.md | 6 ++++++ src/client.ts | 4 +++- src/device.ts | 3 +++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/README_DOCS.md b/README_DOCS.md index fd0838e4..7840e34b 100644 --- a/README_DOCS.md +++ b/README_DOCS.md @@ -89,3 +89,9 @@ adb.listDevices((devices) => { - `time` option in `touch` method is converted to UTC time. - Tracker `change` event emits the same instance of the device instead of creating a new device object every time. - `install` and `uninstall` commands will fail if any other response than `Success` is received. Until V5 the promise could have resolved even when the operation was not successful. + +## Change log + +### 6.2 + +`exec` methods accept `string[]` as an argument. Fix for https://github.com/Maaaartin/adb-ts/issues/13. diff --git a/src/client.ts b/src/client.ts index 09060828..7226339e 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1314,6 +1314,7 @@ export class Client { /** * Executes a given command via adb console interface. + * If cmd contains arguments, they need to be passed as and string[], not string. @see https://github.com/Maaaartin/adb-ts/issues/13 */ public exec(cmd: string | string[]): Promise { return this.execInternal([cmd].flat()); @@ -1321,7 +1322,8 @@ export class Client { /** * Executes a given command on specific device via adb console interface. - * Analogous to `adb -s `. + * Analogous to `adb -s `. + * If cmd contains arguments, they need to be passed as and string[], not string. @see https://github.com/Maaaartin/adb-ts/issues/13 */ public execDevice(serial: string, cmd: string | string[]): Promise { return this.execInternal(['-s', serial].concat(cmd)); diff --git a/src/device.ts b/src/device.ts index f40979e0..b9345f9c 100644 --- a/src/device.ts +++ b/src/device.ts @@ -342,6 +342,9 @@ export class Device implements IDevice { return this.client.killApp(this.id, pkg); } + /** + * If cmd contains arguments, they need to be passed as and string[], not string. @see https://github.com/Maaaartin/adb-ts/issues/13 + */ public exec(cmd: string | string[]): Promise { return this.client.execDevice(this.id, cmd); }