UNPKG

@platform/state

Version:

A small, simple, strongly typed, [rx/observable] state-machine.

257 lines (256 loc) 13.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var tslib_1 = require("tslib"); var test_1 = require("../test"); var rxjs_1 = require("rxjs"); var _1 = require("."); var initial = { count: 0, foo: { list: [] } }; describe('Store', function () { describe('lifecycle', function () { it('constructs', function () { var store = _1.Store.create({ initial: initial }); (0, test_1.expect)(store.isDisposed).to.eql(false); (0, test_1.expect)(store.state).to.not.equal(initial); (0, test_1.expect)(store.state).to.eql(initial); }); it('disposes', function () { var store = _1.Store.create({ initial: initial }); var count = 0; store.dispose$.subscribe(function () { return count++; }); store.dispose(); store.dispose(); (0, test_1.expect)(store.isDisposed).to.eql(true); (0, test_1.expect)(count).to.eql(1); }); it('takes event$ at creation', function () { var event$ = new rxjs_1.Subject(); var store = _1.Store.create({ initial: initial, event$: event$ }); (0, test_1.expect)(store._event$).to.equal(event$); }); }); describe('state', function () { it('returns new immutable object from [state] property', function () { var store = _1.Store.create({ initial: initial }); var state1 = store.state; var state2 = store.state; (0, test_1.expect)(store.state).to.eql(initial); (0, test_1.expect)(store.state).to.not.equal(initial); (0, test_1.expect)(state1).to.eql(store.state); (0, test_1.expect)(state1).to.eql(initial); (0, test_1.expect)(state1).to.not.equal(state2); (0, test_1.expect)(store.state).to.not.equal(initial); }); }); describe('dispatch', function () { it('returns the state object', function () { var state = _1.Store.create({ initial: initial }); var res = state.dispatch({ type: 'TEST/increment', payload: { by: 1 } }); (0, test_1.expect)(res).to.equal(res); }); it('fires dispatch event', function () { var store = _1.Store.create({ initial: initial }); var events = []; store.event$.subscribe(function (e) { return events.push(e); }); store.dispatch({ type: 'TEST/increment', payload: { by: 1 } }); store.dispatch({ type: 'TEST/decrement', payload: { by: 2 } }); (0, test_1.expect)(events.length).to.eql(2); (0, test_1.expect)(events[0].type).to.eql('TEST/increment'); (0, test_1.expect)(events[1].type).to.eql('TEST/decrement'); }); it('fires (via injected event$)', function () { var event$ = new rxjs_1.Subject(); var store = _1.Store.create({ initial: initial, event$: event$ }); var events = []; store.event$.subscribe(function (e) { return events.push(e); }); event$.next({ type: 'TEST/increment', payload: { by: 1 } }); event$.next({ type: 'TEST/decrement', payload: { by: 2 } }); (0, test_1.expect)(events.length).to.eql(2); (0, test_1.expect)(events[0].type).to.eql('TEST/increment'); (0, test_1.expect)(events[1].type).to.eql('TEST/decrement'); }); it('returns copy of the current state object on event', function () { var store = _1.Store.create({ initial: initial }); var states = []; store.on('TEST/increment').subscribe(function (e) { states.push(e.state); states.push(e.state); }); store.dispatch({ type: 'TEST/increment', payload: { by: 1 } }); (0, test_1.expect)(states.length).to.eql(2); (0, test_1.expect)(states[0]).to.eql(store.state); (0, test_1.expect)(states[1]).to.eql(store.state); (0, test_1.expect)(states[0]).to.not.equal(store.state); (0, test_1.expect)(states[1]).to.not.equal(store.state); (0, test_1.expect)(states[0]).to.not.equal(states[1]); }); it('changes the current state (via {...object})', function () { var store = _1.Store.create({ initial: initial }); (0, test_1.expect)(store.state.count).to.eql(0); store.on('TEST/increment').subscribe(function (e) { var count = e.state.count + e.payload.by; var next = tslib_1.__assign(tslib_1.__assign({}, e.state), { count: count }); e.change(next); }); store.on('TEST/decrement').subscribe(function (e) { var count = e.state.count - e.payload.by; var next = tslib_1.__assign(tslib_1.__assign({}, e.state), { count: count }); e.change(next); }); store.dispatch({ type: 'TEST/increment', payload: { by: 1 } }); (0, test_1.expect)(store.state.count).to.eql(1); store.dispatch({ type: 'TEST/decrement', payload: { by: 2 } }); (0, test_1.expect)(store.state.count).to.eql(-1); }); it('changes the current state (via immutable function)', function () { var store = _1.Store.create({ initial: tslib_1.__assign(tslib_1.__assign({}, initial), { bar: { msg: 'hello' } }), }); var before = store.state; (0, test_1.expect)(before.count).to.eql(0); store.on('TEST/increment').subscribe(function (e) { e.change(function (draft) { draft.count += e.payload.by; }); }); store.on('TEST/changeFoo').subscribe(function (e) { e.change(function (draft) { draft.foo.list.push(123); var foo = draft.foo; foo.msg = 'hello'; }); }); store.dispatch({ type: 'TEST/increment', payload: { by: 1 } }); var after1 = store.state; (0, test_1.expect)(before).to.not.equal(after1); (0, test_1.expect)(after1.count).to.eql(1); (0, test_1.expect)(after1.foo).to.equal(before.foo); (0, test_1.expect)(after1.bar).to.equal(before.bar); store.dispatch({ type: 'TEST/changeFoo', payload: {} }); var after2 = store.state; (0, test_1.expect)(after2.foo.list).to.eql([123]); (0, test_1.expect)(after2.foo.msg).to.eql('hello'); (0, test_1.expect)(after2).to.not.equal(after1); (0, test_1.expect)(after2.foo).to.not.equal(after1.foo); (0, test_1.expect)(after2.foo.list).to.not.equal(after1.foo.list); }); it('fires [changing] event', function () { var store = _1.Store.create({ initial: initial }); var events = []; store.changing$.subscribe(function (e) { return events.push(e); }); store.on('TEST/increment').subscribe(function (e) { return e.change(e.state); }); store .on('TEST/changeFoo') .subscribe(function (e) { return e.change(function (draft) { return (draft.foo.list = [1, 2, 3]); }); }); store.dispatch({ type: 'TEST/increment', payload: { by: 1 } }); (0, test_1.expect)(events.length).to.eql(1); (0, test_1.expect)(events[0].isCancelled).to.eql(false); (0, test_1.expect)(events[0].change.type).to.eql('TEST/increment'); store.dispatch({ type: 'TEST/changeFoo', payload: {} }); (0, test_1.expect)(events.length).to.eql(2); (0, test_1.expect)(events[1].isCancelled).to.eql(false); (0, test_1.expect)(events[1].change.type).to.eql('TEST/changeFoo'); }); it('cancels change', function () { var store = _1.Store.create({ initial: initial }); var cancel = false; store.changing$.subscribe(function (e) { if (cancel) { e.cancel(); } }); store.on('TEST/increment').subscribe(function (e) { if (e.payload.by > 0) { var count = e.state.count + e.payload.by; var next = tslib_1.__assign(tslib_1.__assign({}, e.state), { count: count }); e.change(next); } }); store .on('TEST/changeFoo') .subscribe(function (e) { return e.change(function (draft) { return (draft.foo.list = [1, 2, 3]); }); }); (0, test_1.expect)(store.state.count).to.eql(0); store.dispatch({ type: 'TEST/increment', payload: { by: 1 } }); (0, test_1.expect)(store.state.count).to.eql(1); cancel = true; store.dispatch({ type: 'TEST/increment', payload: { by: 99 } }); (0, test_1.expect)(store.state.count).to.eql(1); store.dispatch({ type: 'TEST/changeFoo', payload: {} }); (0, test_1.expect)(store.state.foo.list).to.eql([]); cancel = false; store.dispatch({ type: 'TEST/changeFoo', payload: {} }); (0, test_1.expect)(store.state.foo.list).to.eql([1, 2, 3]); }); it('fires [changed] event', function () { var store = _1.Store.create({ initial: initial }); var events = []; store.changed$.subscribe(function (e) { return events.push(e); }); store.on('TEST/increment').subscribe(function (e) { if (e.payload.by > 0) { var count = e.state.count + e.payload.by; var next = tslib_1.__assign(tslib_1.__assign({}, e.state), { count: count }); e.change(next); } }); store.dispatch({ type: 'TEST/increment', payload: { by: 90 } }); store.dispatch({ type: 'TEST/increment', payload: { by: 0 } }); store.dispatch({ type: 'TEST/increment', payload: { by: 2 } }); (0, test_1.expect)(events.length).to.eql(2); var change1 = events[0]; var change2 = events[1]; (0, test_1.expect)(change1.type).to.eql('TEST/increment'); (0, test_1.expect)(change1.event.type).to.eql('TEST/increment'); (0, test_1.expect)(change1.event.payload.by).to.eql(90); (0, test_1.expect)(change2.type).to.eql('TEST/increment'); (0, test_1.expect)(change2.event.type).to.eql('TEST/increment'); (0, test_1.expect)(change2.event.payload.by).to.eql(2); (0, test_1.expect)(change1.from.count).to.eql(0); (0, test_1.expect)(change1.to.count).to.eql(90); (0, test_1.expect)(change2.from.count).to.eql(90); (0, test_1.expect)(change2.to.count).to.eql(92); }); }); describe('epics', function () { it('dispatches a follow-on event (sync)', function () { var store = _1.Store.create({ initial: initial }); var events = []; store.event$.subscribe(function (e) { return events.push(e); }); store.on('TEST/increment').subscribe(function (e) { e.dispatch({ type: 'TEST/decrement', payload: { by: 2 } }); }); store.dispatch({ type: 'TEST/increment', payload: { by: 1 } }); (0, test_1.expect)(events.length).to.eql(2); (0, test_1.expect)(events[0].type).to.eql('TEST/increment'); (0, test_1.expect)(events[1].type).to.eql('TEST/decrement'); }); it('dispatches a follow-on event (async)', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () { var store, events; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: store = _1.Store.create({ initial: initial }); events = []; store.event$.subscribe(function (e) { return events.push(e); }); store.on('TEST/increment').subscribe(function (e) { return tslib_1.__awaiter(void 0, void 0, void 0, function () { return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: return [4, test_1.time.wait(3)]; case 1: _a.sent(); e.dispatch({ type: 'TEST/decrement', payload: { by: 2 } }); return [2]; } }); }); }); (0, test_1.expect)(events.length).to.eql(0); store.dispatch({ type: 'TEST/increment', payload: { by: 1 } }); (0, test_1.expect)(events.length).to.eql(1); return [4, test_1.time.wait(10)]; case 1: _a.sent(); (0, test_1.expect)(events.length).to.eql(2); return [2]; } }); }); }); }); });