简体   繁体   中英

How to mock childprocess.exec in TS

export function executeCommandPromise(file: string, command: string) {
  return new Promise((resolve, reject) => {
    exec(command, { cwd: `${file}` }, (error: ExecException | null, stdout: string, stderr: string) => {
      if (error) {
        console.warn(error);
        reject(error);
      }
      resolve(capRunnable);
    });
  });
}

I want to create test that will stub the exec command the problem that the exec is called to callback function and I want to control on the stdout

I tried to do something like

let sandbox = sinon.sandbox.create();

let event= new events.EventEmitter();


sandbox.stub(child_process, 'exec').returns(event);

but it did't work and I didn't know how to return result to the stdout

Here is the unit test solution:

index.ts :

import cp, { ExecException } from 'child_process';

const capRunnable = 'capRunnable';

export function executeCommandPromise(file: string, command: string) {
  return new Promise((resolve, reject) => {
    cp.exec(command, { cwd: `${file}` }, (error: ExecException | null, stdout: string, stderr: string) => {
      if (error) {
        console.warn(error);
        reject(error);
      }
      resolve(capRunnable);
    });
  });
}

index.spec.ts :

import { executeCommandPromise } from './';
import cp, { ChildProcess, ExecException } from 'child_process';

describe('executeCommandPromise', () => {
  afterEach(() => {
    jest.restoreAllMocks();
  });
  test('should exec command correctly', async () => {
    let execCallback: (error: ExecException | null, stdout: string, stderr: string) => void;
    jest
      .spyOn(cp, 'exec')
      .mockImplementation(function(
        this: ChildProcess,
        command: string,
        options: any,
        callback?: (error: ExecException | null, stdout: string, stderr: string) => void
      ): ChildProcess {
        if (callback) {
          execCallback = callback;
        }
        return this;
      });
    const actualValue = executeCommandPromise('somefile', 'ls -a');
    execCallback!(null, '', '');
    await expect(actualValue).resolves.toBe('capRunnable');
    expect(cp.exec).toBeCalledWith('ls -a', { cwd: 'somefile' }, execCallback!);
  });

  test('should throw error when exec command failed', async () => {
    let execCallback: (error: ExecException | null, stdout: string, stderr: string) => void;
    jest
      .spyOn(cp, 'exec')
      .mockImplementation(function(
        this: ChildProcess,
        command: string,
        options: any,
        callback?: (error: ExecException | null, stdout: string, stderr: string) => void
      ): ChildProcess {
        if (callback) {
          execCallback = callback;
        }
        return this;
      });
    const actualValue = executeCommandPromise('somefile', 'ls -a');
    execCallback!(new Error('some error happened'), '', '');
    await expect(actualValue).rejects.toThrowError('some error happened');
    expect(cp.exec).toBeCalledWith('ls -a', { cwd: 'somefile' }, execCallback!);
  });
});

Unit test result with 100% coverage:

 PASS  src/stackoverflow/57589104/index.spec.ts (8.518s)
  executeCommandPromise
    ✓ should exec command correctly (15ms)
    ✓ should throw error when exec command failed (10ms)

  console.warn src/stackoverflow/57589104/index.ts:469
    Error: some error happened
        at /Users/ldu020/workspace/github.com/mrdulin/jest-codelab/src/stackoverflow/57589104/index.spec.ts:45:19
        at step (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/src/stackoverflow/57589104/index.spec.ts:33:23)
        at Object.next (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/src/stackoverflow/57589104/index.spec.ts:14:53)
        at /Users/ldu020/workspace/github.com/mrdulin/jest-codelab/src/stackoverflow/57589104/index.spec.ts:8:71
        at new Promise (<anonymous>)
        at Object.<anonymous>.__awaiter (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/src/stackoverflow/57589104/index.spec.ts:4:12)
        at Object.<anonymous> (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/src/stackoverflow/57589104/index.spec.ts:29:55)
        at Object.asyncJestTest (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:102:37)
        at resolve (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/node_modules/jest-jasmine2/build/queueRunner.js:43:12)
        at new Promise (<anonymous>)
        at mapper (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/node_modules/jest-jasmine2/build/queueRunner.js:26:19)
        at promise.then (/Users/ldu020/workspace/github.com/mrdulin/jest-codelab/node_modules/jest-jasmine2/build/queueRunner.js:73:41)
        at process._tickCallback (internal/process/next_tick.js:68:7)

----------|----------|----------|----------|----------|-------------------|
File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files |      100 |      100 |      100 |      100 |                   |
 index.ts |      100 |      100 |      100 |      100 |                   |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        10.086s

Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/57589104

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM