Skip to content

Commit

Permalink
feat: new method stateTransitionRejection() called when a transition …
Browse files Browse the repository at this point in the history
…rejects
  • Loading branch information
arlac77 committed Dec 26, 2015
1 parent 2645192 commit b568569
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 14 deletions.
52 changes: 39 additions & 13 deletions StateTransitionMixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,20 @@ module.exports.StateTransitionMixin = (superclass, actions, currentState) => cla
return Promise.reject(new Error(`Can't ${action.name} ${this} in ${this.state} state`));
}

/**
* Called when the state transtinio implementation Promise rejects.
* Resets the transition
* @return {Promise} rejecting promise
*/
stateTransitionRejection(rejected) {
//this.error(level => `Executing ${this._transition.name} transition leads to ${rejected}`);
this.state = 'failed';
this._transitionPromise = undefined;
this._transition = undefined;

return Promise.reject(rejected);
}

/**
* To be overwritten
* Called when the state changes
Expand Down Expand Up @@ -71,6 +85,25 @@ function thisResolverPromise() {
return Promise.resolve(this);
}

/**
* Defines methods to perfom the state transitions.
* States are traversed in the following way:
* current -> during -> final
* If the step is not in one of the transitions current
* states and also not already in the transitions final
* state a rejecting promise will be delivered from the
* generated function. In the 'during' state a function
* named '_' + <transitions name> (sample: '_start()')
* will be called first.
* It is expected that this function delivers a promise.
* Special handling of consequent transitions:
* While in a during state the former delivered primise will be
* delivered again. This enshures that several consequent
* transitions in a row will be fullfiled by the same promise.
* There can only be one transition in place at a given point in time.
* @param {Object} object where we define the metods
* @param {Object} actions object describing the state transitions
*/
module.exports.defineActionMethods = function (object, actions) {
//console.log(`${JSON.stringify(actions,undefined,1)}`);

Expand All @@ -87,11 +120,11 @@ module.exports.defineActionMethods = function (object, actions) {
Object.defineProperty(object, actionName, {
value: function () {
if (this._transition) {
if (this.state === this._transition.during) {
return this._transitionPromise;
}
if (this.state === this._transition.target) {
return Promise.resolve(this);
switch (this.state) {
case this._transition.during:
return this._transitionPromise;
case this._transition.target:
return Promise.resolve(this);
}
}
if (action.transitions[this.state]) {
Expand All @@ -104,14 +137,7 @@ module.exports.defineActionMethods = function (object, actions) {
this._transitionPromise = undefined;
this._transition = undefined;
return this;
}, rejected => {
this.error(level => `Executing ${this._transition.name} transition leads to ${rejected}`);

this.state = 'failed';
this._transitionPromise = undefined;
this._transition = undefined;
return Promise.reject(reject);
});
}, rejected => this.stateTransitionRejection(rejected));

return this._transitionPromise;
} else {
Expand Down
18 changes: 17 additions & 1 deletion tests/simple.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,17 @@ const actions = stm.prepareActions({

class BaseClass {}

var shouldReject = false;

class StatefullClass extends stm.StateTransitionMixin(BaseClass, actions, 'stopped') {
_start() {
return new Promise((f, r) => {
setTimeout(() => {
f(this)
if (shouldReject) {
r(new Error("always reject"));
} else {
f(this);
}
}, 10);
});
}
Expand Down Expand Up @@ -101,4 +107,14 @@ describe('states', function () {
});
});

it('handle failure while starting', function (done) {
o1.stop().then(() => {
shouldReject = true;
assert.equal(o1.state, 'stopped');
o1.start().then(() => {}).catch(e => {
assert.equal(o1.state, 'failed');
done();
});
});
});
});

0 comments on commit b568569

Please sign in to comment.