From f690cdcac2ca84de53592265b434bc0658da5c03 Mon Sep 17 00:00:00 2001 From: ssube Date: Mon, 30 Mar 2020 23:37:58 -0500 Subject: [PATCH] fix(test): begin covering child process utils --- docs/api/js-utils.childoptions.cwd.md | 11 ----- docs/api/js-utils.childoptions.env.md | 11 ----- docs/api/js-utils.childoptions.md | 5 +- docs/api/js-utils.childoptions.timeout.md | 11 ----- docs/api/js-utils.childspawner.md | 2 +- docs/api/js-utils.waitforchild.md | 4 +- src/utils/Child.ts | 21 ++++++--- test/utils/TestChild.ts | 56 +++++++++++++++++++++++ 8 files changed, 75 insertions(+), 46 deletions(-) delete mode 100644 docs/api/js-utils.childoptions.cwd.md delete mode 100644 docs/api/js-utils.childoptions.env.md delete mode 100644 docs/api/js-utils.childoptions.timeout.md create mode 100644 test/utils/TestChild.ts diff --git a/docs/api/js-utils.childoptions.cwd.md b/docs/api/js-utils.childoptions.cwd.md deleted file mode 100644 index 690079b0..00000000 --- a/docs/api/js-utils.childoptions.cwd.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [@apextoaster/js-utils](./js-utils.md) > [ChildOptions](./js-utils.childoptions.md) > [cwd](./js-utils.childoptions.cwd.md) - -## ChildOptions.cwd property - -Signature: - -```typescript -cwd: string; -``` diff --git a/docs/api/js-utils.childoptions.env.md b/docs/api/js-utils.childoptions.env.md deleted file mode 100644 index f93e870e..00000000 --- a/docs/api/js-utils.childoptions.env.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [@apextoaster/js-utils](./js-utils.md) > [ChildOptions](./js-utils.childoptions.md) > [env](./js-utils.childoptions.env.md) - -## ChildOptions.env property - -Signature: - -```typescript -env: Array>; -``` diff --git a/docs/api/js-utils.childoptions.md b/docs/api/js-utils.childoptions.md index 02bb5595..baaa4c4f 100644 --- a/docs/api/js-utils.childoptions.md +++ b/docs/api/js-utils.childoptions.md @@ -7,7 +7,7 @@ Signature: ```typescript -export interface ChildOptions +export interface ChildOptions extends ChildProcessOptions ``` ## Properties @@ -16,7 +16,4 @@ export interface ChildOptions | --- | --- | --- | | [args](./js-utils.childoptions.args.md) | Array<string> | | | [command](./js-utils.childoptions.command.md) | string | | -| [cwd](./js-utils.childoptions.cwd.md) | string | | -| [env](./js-utils.childoptions.env.md) | Array<NameValuePair<string>> | | -| [timeout](./js-utils.childoptions.timeout.md) | number | | diff --git a/docs/api/js-utils.childoptions.timeout.md b/docs/api/js-utils.childoptions.timeout.md deleted file mode 100644 index 77f66c81..00000000 --- a/docs/api/js-utils.childoptions.timeout.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [@apextoaster/js-utils](./js-utils.md) > [ChildOptions](./js-utils.childoptions.md) > [timeout](./js-utils.childoptions.timeout.md) - -## ChildOptions.timeout property - -Signature: - -```typescript -timeout: number; -``` diff --git a/docs/api/js-utils.childspawner.md b/docs/api/js-utils.childspawner.md index 4d062bd0..b6be08e9 100644 --- a/docs/api/js-utils.childspawner.md +++ b/docs/api/js-utils.childspawner.md @@ -7,5 +7,5 @@ Signature: ```typescript -export declare type ChildSpawner = typeof spawn; +export declare type ChildSpawner = (command: string, args: Array, options: Partial) => ChildStreams; ``` diff --git a/docs/api/js-utils.waitforchild.md b/docs/api/js-utils.waitforchild.md index 7740ff62..6adac2d4 100644 --- a/docs/api/js-utils.waitforchild.md +++ b/docs/api/js-utils.waitforchild.md @@ -7,14 +7,14 @@ Signature: ```typescript -export declare function waitForChild(child: ChildProcessWithoutNullStreams): Promise; +export declare function waitForChild(child: ChildStreams): Promise; ``` ## Parameters | Parameter | Type | Description | | --- | --- | --- | -| child | ChildProcessWithoutNullStreams | | +| child | ChildStreams | | Returns: diff --git a/src/utils/Child.ts b/src/utils/Child.ts index 2b8ea0e3..05b62744 100644 --- a/src/utils/Child.ts +++ b/src/utils/Child.ts @@ -1,4 +1,4 @@ -import { ChildProcessWithoutNullStreams, spawn } from 'child_process'; +import { ChildProcessWithoutNullStreams, spawn, ChildProcess } from 'child_process'; import { BaseError } from 'noicejs'; import { Writable } from 'stream'; @@ -7,28 +7,37 @@ import { ChildProcessError } from '../error/ChildProcessError'; import { encode } from './Buffer'; import { NameValuePair } from './Map'; -export interface ChildOptions { - args: Array; - command: string; +export interface ChildProcessOptions { cwd: string; env: Array>; timeout: number; } +export interface ChildOptions extends ChildProcessOptions { + args: Array; + command: string; +} + export interface ChildResult { status: number; stderr: string; stdout: string; } -export type ChildSpawner = typeof spawn; +export type ChildStreams = ChildProcessWithoutNullStreams; + +export type ChildSpawner = ( + command: string, + args: Array, + options: Partial +) => ChildStreams; const CHILD_ENCODING = 'utf-8'; const CHILD_EVENT = 'child process emitted error event'; const CHILD_STATUS = 'child process exited with error status'; const CHILD_OUTPUT = 'child process emitted error output'; -export function waitForChild(child: ChildProcessWithoutNullStreams): Promise { +export function waitForChild(child: ChildStreams): Promise { return new Promise((res, rej) => { const stderr: Array = []; const stdout: Array = []; diff --git a/test/utils/TestChild.ts b/test/utils/TestChild.ts new file mode 100644 index 00000000..69f49d12 --- /dev/null +++ b/test/utils/TestChild.ts @@ -0,0 +1,56 @@ +import { expect } from 'chai'; + +import { mustExist, Optional } from '../../src/utils'; +import { ChildStreams, waitForChild } from '../../src/utils/Child'; +import { describeLeaks, itLeaks } from '../helpers/async'; +import { ChildProcessError } from '../../src'; + +type Closer = (status: number) => Promise; + +function createChild(): ChildStreams & { closer: Optional } { + return { + closer /* Optional */ : undefined, + on(event: string, fn: Closer) { + if (event === 'close') { + this.closer = fn; + } + }, + stderr: { + on() { + /* noop */ + }, + }, + stdout: { + on() { + /* noop */ + }, + }, + /* eslint-disable @typescript-eslint/no-explicit-any */ + } as any; +} + +describeLeaks('child process utils', async () => { + describeLeaks('wait for child helper', async () => { + itLeaks('should read stdout data', async () => { + const child = createChild(); + + const resultPromise = waitForChild(child); + await mustExist(child.closer)(0); + + const result = await resultPromise; + expect(result.status).to.equal(0); + }); + + itLeaks('should read stderr data'); + itLeaks('should resolve on success status'); + + itLeaks('should reject on failure status', async () => { + const child = createChild(); + + const resultPromise = waitForChild(child); + await mustExist(child.closer)(1); + + return expect(resultPromise).to.eventually.be.rejectedWith(ChildProcessError); + }); + }); +});