exec-sh.js
  1  /* global describe, it, beforeEach, afterEach */
  2  var execSh = require('..')
  3  var assert = require('assert')
  4  var sinon = require('sinon')
  5  var cp = require('child_process')
  6  
  7  describe('exec-sh', function () {
  8    describe('module.exports', function () {
  9      it('should export a single function', function () {
 10        assert.strictEqual(typeof execSh, 'function')
 11      })
 12  
 13      it('should export promise interface', function () {
 14        assert.strictEqual(typeof execSh.promise, 'function')
 15      })
 16    })
 17  
 18    describe('#execSh() arguments', function () {
 19      var spawn, exitCode, stream
 20  
 21      stream = {
 22        on: function (e, c) {
 23          if (e === 'data') {
 24            // execute callback two times to check if stream
 25            // aggregation works correctly
 26            c('1')
 27            c('2')
 28          }
 29        }
 30      }
 31  
 32      beforeEach(function () {
 33        exitCode = 0
 34        spawn = sinon.stub(cp, 'spawn')
 35        spawn.returns({
 36          spawn_return: true,
 37          on: function (e, c) {
 38            if (e === 'close') {
 39              c(exitCode)
 40            }
 41          },
 42          stdout: stream,
 43          stderr: stream
 44        })
 45      })
 46  
 47      afterEach(function () {
 48        cp.spawn.restore()
 49      })
 50  
 51      it('should pass command to spawn function', function () {
 52        execSh('command')
 53        sinon.assert.calledOnce(spawn)
 54        assert.strictEqual('command', spawn.getCall(0).args[1][1])
 55      })
 56  
 57      it('should accept array of commands to run', function () {
 58        execSh(['command1', 'command2'])
 59        sinon.assert.calledOnce(spawn)
 60        assert.strictEqual('command1;command2', spawn.getCall(0).args[1][1])
 61      })
 62  
 63      it('should accept true as options argument', function () {
 64        execSh('command', true)
 65        sinon.assert.calledOnce(spawn)
 66        assert.strictEqual(spawn.getCall(0).args[2].stdio, null)
 67      })
 68  
 69      it('should merge defaults with options', function () {
 70        var options = { key: 'value' }
 71        var expectedOptions = {
 72          key: 'value',
 73          stdio: 'inherit'
 74        }
 75        execSh('command', options)
 76        assert.deepStrictEqual(spawn.getCall(0).args[2], expectedOptions)
 77      })
 78  
 79      it('should allow overriding default options', function () {
 80        var options = { foo: 'bar', stdio: null }
 81        var expectedOptions = {
 82          foo: 'bar',
 83          stdio: null
 84        }
 85        execSh('command', options)
 86        assert.deepStrictEqual(spawn.getCall(0).args[2], expectedOptions)
 87      })
 88  
 89      it('should allow passing nested environment options', function () {
 90        var options = {
 91          env: {
 92            key1: 'value 1',
 93            key2: 'value 2'
 94          }
 95        }
 96        var expectedOptions = {
 97          env: {
 98            key1: 'value 1',
 99            key2: 'value 2'
100          },
101          stdio: 'inherit'
102        }
103        execSh('command', options)
104        assert.deepStrictEqual(spawn.getCall(0).args[2], expectedOptions)
105      })
106  
107      it("should accept optional 'callback' parameter", function () {
108        var callback = sinon.spy()
109        execSh('command', callback)
110        execSh('command', { key: 'value' }, callback)
111        sinon.assert.callCount(callback, 2)
112      })
113  
114      it("should use 'cmd /C' command prefix on windows", function () {
115        var platform = process.platform
116        Object.defineProperty(process, 'platform', { value: 'win32' })
117        execSh('command')
118        Object.defineProperty(process, 'platform', { value: platform })
119  
120        sinon.assert.calledOnce(spawn)
121        assert.strictEqual(spawn.getCall(0).args[0], 'cmd')
122      })
123  
124      it("should use 'sh -c' command prefix on *nix", function () {
125        var platform = process.platform
126        process.platform = 'linux'
127        execSh('command')
128        process.platform = platform
129  
130        sinon.assert.calledOnce(spawn)
131        assert.strictEqual(spawn.getCall(0).args[1][0], '-c')
132        assert.strictEqual(spawn.getCall(0).args[0], 'sh')
133      })
134  
135      it('should return spawn() result', function () {
136        assert(execSh('command').spawn_return)
137      })
138  
139      it('should aggregate stdoout and stderr', function (done) {
140        execSh('command', function (_err, stdout, stderr) {
141          assert.strictEqual(stdout, '12')
142          assert.strictEqual(stderr, '12')
143          done()
144        })
145      })
146  
147      it('should catch exceptions thrown by spawn', function (done) {
148        spawn.throws()
149        execSh('command', function (err, stdout, stderr) {
150          assert(err instanceof Error)
151          done()
152        })
153      })
154  
155      it('should return empty stdout and stderr when spawn throws', function (done) {
156        spawn.throws()
157        stream = null
158        execSh('command', function (_err, stdout, stderr) {
159          assert.strictEqual(stderr, '')
160          assert.strictEqual(stdout, '')
161          done()
162        })
163      })
164  
165      it('should run callback with error when shell exit with non-zero code', function (done) {
166        exitCode = 1
167        execSh('command', function (err) {
168          assert(err instanceof Error)
169          assert.strictEqual(exitCode, err.code)
170          done()
171        })
172      })
173  
174      it('promise interface: should return promise', function () {
175        assert(execSh.promise('command') instanceof Promise)
176      })
177  
178      it('promise interface: should resolve with stderr and stdout', function (done) {
179        execSh.promise('command').then(function (data) {
180          assert.ok('stdout' in data)
181          assert.ok('stderr' in data)
182          done()
183        })
184      })
185  
186      it('promise interface: should reject promise when exceptions thrown by spawn', function (done) {
187        spawn.throws()
188        execSh.promise('command').catch(function (err) {
189          assert(err instanceof Error)
190          done()
191        })
192      })
193    })
194  })