exec-sh.js 5.4 KB

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