diff --git a/src/Actions.js b/src/Actions.js index ad8a26e..c417bc2 100644 --- a/src/Actions.js +++ b/src/Actions.js @@ -1,4 +1,5 @@ import stampit from 'stampit'; +import warning from 'warning'; import debugFactory from 'debug'; import { Observable, @@ -10,6 +11,7 @@ import { import waitFor from './waitFor'; +const __DEV__ = process.env.NODE_ENV !== 'production'; const { checkDisposed } = Disposable; const assign = Object.assign; const debug = debugFactory('thundercats:actions'); @@ -50,6 +52,7 @@ export function create(shouldBind, { name, map }) { const observers = []; const actionDisposable = new CompositeDisposable(); const actionStart = new Subject(); + const actionEnd = new Subject(); const maybeBound = shouldBind ? map.bind(this) : map; @@ -81,6 +84,9 @@ export function create(shouldBind, { name, map }) { .doOnNext( value => observers.forEach(observer => observer.onNext(value)) ) + .doOnCompleted( + () => actionEnd.onNext() + ) .subscribe( () => debug('%s onNext', name), err => { @@ -123,10 +129,25 @@ export function create(shouldBind, { name, map }) { }; action.waitFor = function() { + /* istanbul ignore else */ + if (__DEV__) { + warning( + false, + 'action.waitFor is deprecated and will be removed in ' + + 'the next version of thundercats' + ); + } return actionStart .flatMap(payload => waitFor(...arguments).map(() => payload)); }; + // NOTE: not public API. May change or be removed at any time + action.__duration = function __duration() { + return actionStart + .flatMap(actionEnd) + .first(); + }; + action._subscribe = function subscribeToAction(observer) { // in next major version this should check if action // has been stopped or disposed and act accordingly diff --git a/test/action.js b/test/action.js index 190e7f3..7f280ac 100644 --- a/test/action.js +++ b/test/action.js @@ -275,6 +275,41 @@ describe('Actions', function() { }); }); + describe('internal lifecycle hooks', function() { + it('should have a duration observable', () => { + const catActions = Actions({ purr: null })(); + assert( + !!catActions.purr.__duration, + 'actions should have a __durations property' + ); + }); + + it('should on call __duration once per action', () => { + const spy = sinon.spy(); + const spy2 = sinon.spy(); + const catActions = Actions({ purr: null })(); + catActions.purr.__duration().subscribe(spy); + catActions.purr(Observable.of(1, 2, 3)); + assert( + spy.calledOnce, + 'duration Observer was called more than once' + ); + + catActions.purr.__duration().subscribe(spy2); + catActions.purr(Observable.of(1, 2, 3)); + + assert( + spy.calledOnce, + 'duration Observable spy was called more than once' + ); + + assert( + spy2.calledOnce, + 'duration Observable spy was called more than once' + ); + }); + }); + describe('disposal', function() { let catActions;