Skip to content

Commit

Permalink
feat(actions): Implement async actions
Browse files Browse the repository at this point in the history
Actions can now be function that returns a Promise.
  • Loading branch information
mattallty committed Feb 27, 2017
1 parent 6b01db5 commit afef8b2
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 30 deletions.
10 changes: 8 additions & 2 deletions lib/command.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const InvalidArgumentValueError = require('./error/invalid-argument-value');
const MissingOptionError = require('./error/missing-option');
const NoActionError = require('./error/no-action-error');
const WrongNumberOfArgumentError = require('./error/wrong-num-of-arg');
const Promise = require('bluebird');

/**
* Command class
Expand Down Expand Up @@ -381,7 +382,6 @@ class Command extends GetterSetter {
*
* @param {Object} args - Arguments
* @param {Object} options - Options
* @returns {*}
* @private
*/
_run(args, options) {
Expand All @@ -392,7 +392,13 @@ class Command extends GetterSetter {
this._program
));
}
return this._action.apply(this, [args, options, this._logger]);
const actionResults = this._action.apply(this, [args, options, this._logger]);
const response = Promise.resolve(actionResults);
response
.catch(err => {
err = err instanceof Error ? err : new Error(err);
return this._program.fatalError(err);
})
}

/**
Expand Down
128 changes: 128 additions & 0 deletions tests/actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
"use strict";

/* global Program, logger, should, makeArgv, sinon */

const Promise = require('bluebird');

describe('Setting up no action()', () => {

it(`should throw NoActionError`, () => {

const program = new Program();

program
.logger(logger)
.version('1.0.0')
.command('foo', 'My foo');

const error = sinon.stub(program, "fatalError", function(err) {
should(err.name).eql('NoActionError');
});

program.parse(makeArgv('foo'));

const count = error.callCount;
error.restore();
should(count).be.eql(1);
program.reset();
});

});


describe('Setting up a sync action', () => {

it(`should call this action`, () => {

const program = new Program();
const action = sinon.spy();

program
.logger(logger)
.version('1.0.0')
.command('foo', 'My foo')
.action(action);

program.parse(makeArgv('foo'));

should(action.callCount).be.eql(1);

program.reset();
});

});


describe('Setting up a async action', () => {

it(`should succeed for a resolved promise`, () => {

const program = new Program();
const action = function() {
return Promise.resolve('foo')
};
const stub = sinon.spy(action);

program
.logger(logger)
.version('1.0.0')
.command('foo', 'My foo')
.action(stub);

program.parse(makeArgv('foo'));

should(stub.callCount).be.eql(1);
program.reset();

});

it(`should fatalError() for a rejected promise (error string)`, (done) => {

const program = new Program();
const action = function() {
return Promise.reject('Failed!')
};
const stub = sinon.spy(action);
const fatalError = sinon.stub(program, "fatalError");

program
.logger(logger)
.version('1.0.0')
.command('foo', 'My foo')
.action(stub);

program.parse(makeArgv('foo'));

setImmediate(function () {
should(stub.callCount).be.eql(1);
should(fatalError.callCount).be.eql(1);
done()
});

});
it(`should fatalError() for a rejected promise (error object)`, (done) => {

const program = new Program();
const action = function() {
return Promise.reject(new Error('Failed!'))
};
const stub = sinon.spy(action);
const fatalError = sinon.stub(program, "fatalError");

program
.logger(logger)
.version('1.0.0')
.command('foo', 'My foo')
.action(stub);

program.parse(makeArgv('foo'));

setImmediate(function () {
should(stub.callCount).be.eql(1);
should(fatalError.callCount).be.eql(1);
done()
});

});

});
28 changes: 0 additions & 28 deletions tests/no-action.js

This file was deleted.

0 comments on commit afef8b2

Please sign in to comment.