Skip to content

Commit

Permalink
Merge f401c6e into eabec6b
Browse files Browse the repository at this point in the history
  • Loading branch information
acburdine committed Sep 21, 2016
2 parents eabec6b + f401c6e commit d94bf96
Show file tree
Hide file tree
Showing 3 changed files with 197 additions and 1 deletion.
2 changes: 1 addition & 1 deletion lib/utils/npm.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ module.exports = function npm(npmArgs, npmConfig, options) {
return resolve(output);
}

return resolve(code || signal);
return resolve(signal);
});
});
};
178 changes: 178 additions & 0 deletions test/unit/utils/npm-spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
/* jshint expr:true */
var expect = require('chai').expect,
rewire = require('rewire'),
sinon = require('sinon'),
stream = require('stream'),
ChildProcess = require('../../utils/child_process'),

npm = rewire('../../../lib/utils/npm');

describe('Unit: npm', function () {
var currentEnv,
cp, spawn, reset;

beforeEach(function () {
currentEnv = process.env;
process.env = {};

cp = new ChildProcess();
spawn = sinon.stub().returns(cp);
reset = npm.__set__('spawn', spawn);
});

afterEach(function () {
process.env = currentEnv;
reset();

cp = null;
spawn = null;
});

it('spawns npm process with no arguments correctly', function () {
var promise = npm();

cp.emit('exit');

return promise.then(function () {
expect(spawn.calledOnce).to.be.true;
expect(spawn.args[0]).to.be.ok;
expect(spawn.args[0]).to.have.lengthOf(3);
expect(spawn.args[0][1]).to.deep.equal([]);
});
});

it('spawns npm process with correct arguments', function () {
var promise = npm(['cache', 'clear']);

cp.emit('exit');

return promise.then(function () {
expect(spawn.calledOnce).to.be.true;
expect(spawn.args[0]).to.be.ok;
expect(spawn.args[0]).to.have.lengthOf(3);
expect(spawn.args[0][1]).to.deep.equal(['cache', 'clear']);
});
});

it('disables npm progress bar by default', function () {
var promise = npm();

cp.emit('exit');

return promise.then(function () {
expect(spawn.calledOnce).to.be.true;
expect(spawn.args[0]).to.be.ok;
expect(spawn.args[0]).to.have.lengthOf(3);
expect(spawn.args[0][2]).to.be.an('object');
expect(spawn.args[0][2].env).to.be.an('object');
expect(spawn.args[0][2].env.npm_config_progress).to.be.false;
});
});

it('passes npm config options correctly to environment variables', function () {
var promise = npm([], {loglevel: 'quiet', color: 'always'});

cp.emit('exit');

return promise.then(function () {
expect(spawn.calledOnce).to.be.true;
expect(spawn.args[0]).to.be.ok;
expect(spawn.args[0]).to.have.lengthOf(3);
expect(spawn.args[0][2]).to.be.an('object');
expect(spawn.args[0][2].env).to.be.an('object');
expect(spawn.args[0][2].env).to.deep.equal({
npm_config_progress: false,
npm_config_loglevel: 'quiet',
npm_config_color: 'always'
});
});
});

it('correctly passes through options and excludes captureOutput', function () {
var promise = npm([], {}, {cwd: 'test', captureOutput: false});

cp.emit('exit');

return promise.then(function () {
expect(spawn.calledOnce).to.be.true;
expect(spawn.args[0]).to.be.ok;
expect(spawn.args[0]).to.have.lengthOf(3);
expect(spawn.args[0][2]).to.be.an('object');
expect(spawn.args[0][2].cwd).to.equal('test');
expect(spawn.args[0][2].captureOutput).to.be.undefined;
});
});

it('rejects with error if one is emitted', function () {
var promise = npm();

cp.emit('error', new Error('test error'));

return promise.then(function () {
throw new Error('Promise should not have resolved');
}).catch(function (error) {
expect(error).to.be.an('error');
expect(error.message).to.equal('test error');
});
});

it('rejects with error code if one is emitted on exit', function () {
var promise = npm();

cp.emit('exit', 42); // the answer to life, the universe, and everything

return promise.then(function () {
throw new Error('Promise should not have resolved');
}).catch(function (code) {
expect(code).to.not.be.an('error');
expect(code).to.equal(42);
});
});

it('correctly captures the npm output and returns it when output is a string', function () {
var stdout = stream.Readable(),
promise;

stdout._read = function () { stdout.push(null); };

cp.stdout = stdout;
promise = npm([], {}, {captureOutput: true});

stdout.emit('data', 'test');
cp.emit('exit');

return promise.then(function (output) {
expect(output).to.be.a('string');
expect(output).to.equal('test');
});
});

it('correctly captures the npm output and returns it when output is a string', function () {
var stdout = stream.Readable(),
buffer = Buffer.from ? Buffer.from('test') : new Buffer('test'),
promise;

stdout._read = function () { stdout.push(null); };

cp.stdout = stdout;
promise = npm([], {}, {captureOutput: true});

stdout.emit('data', buffer);
cp.emit('exit');

return promise.then(function (output) {
expect(output).to.be.a('string');
expect(output).to.equal('test');
});
});

it('correctly returns the signal when output is off and signal is given', function () {
var promise = npm();

cp.emit('exit', null, 'test'); // the answer to life, the universe, and everything

return promise.then(function (signal) {
expect(signal).to.equal('test');
});
});
});
18 changes: 18 additions & 0 deletions test/utils/child_process.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// This exists because Node v0.12 doesn't export the ChildProcess class.
// We've implemented a simple version just for testing
/* jscs:disable requireMultipleVarDecl */
var ChildProcess = require('child_process').ChildProcess;

if (ChildProcess) {
module.exports = ChildProcess;
} else {
var EventEmitter = require('events').EventEmitter,
util = require('util');

ChildProcess = function ChildProcess() {
EventEmitter.call(this);
};
util.inherits(ChildProcess, EventEmitter);

module.exports = ChildProcess;
}

0 comments on commit d94bf96

Please sign in to comment.