UNPKG

d2-ui

Version:
285 lines (217 loc) 8.26 kB
import Store from '../../src/store/Store'; import {Observable, TestScheduler, ReactiveTest} from 'rx'; const onNext = ReactiveTest.onNext; function eventually(callback) { return new Promise((resolve, reject) => { setTimeout(() => { try { const value = callback(); resolve(value); } catch (e) { reject(e); } }); }); } describe('Store', () => { let store; let testScheduler; beforeEach(() => { testScheduler = new TestScheduler(); store = Store.create(); }); it('should be a function', () => { expect(Store).to.be.instanceof(Function); }); describe('state', () => { it('should have a state property that is undefined on default', () => { expect(store.state).to.be.undefined; }); it('should be initialized after a value was passed to constructor', () => { store = new Store({name: 'Mark'}); return eventually(() => { expect(store.state).to.deep.equal({name: 'Mark'}); }); }); }); describe('with Promise as initial value', () => { it('should resolve the promise and set it as the value', () => { store = new Store(Promise.resolve({name: 'Mark'})); return eventually(() => { expect(store.state).to.deep.equal({name: 'Mark'}); }); }); it('should reject the value not set the state', () => { store = new Store(Promise.reject(new Error('Could not load value'))); return eventually(() => { expect(store.state).to.deep.equal(undefined); }); }); }); describe('emitState', () => { it('should have emitted the intial state when the store was initialized with a state', () => { const onNextSpy = spy(); store = new Store({name: 'Mark'}); store.subscribe(onNextSpy); return eventually(() => { expect(store.state).to.deep.equal({name: 'Mark'}); }); }); it('should emit the newly set state', () => { const onNextSpy = spy(); store = new Store(); store.setState({name: 'Mark'}); store.subscribe(onNextSpy); expect(onNextSpy).to.be.calledWith({name: 'Mark'}); }); it('should emit an error when the initial promise fails', () => { const onErrorSpy = spy(); store = new Store(Promise.reject(new Error('Could not load value'))); store.subscribe(undefined, onErrorSpy); return eventually(() => { expect(onErrorSpy).to.be.called; }); }); it('should not emit an undefined value if no inital value has been given', () => { const onNextSpy = spy(); store = new Store(); store.subscribe(onNextSpy); return eventually(() => { expect(onNextSpy).not.to.be.called; }); }); }); describe('setState', () => { it('should be a method', () => { expect(store.setState).to.be.instanceof(Function); }); it('should set the state', () => { store.setState({name: 'Mark'}); expect(store.state).to.deep.equal({name: 'Mark'}); }); }); describe('getState', () => { it('should be a method', () => { expect(store.getState).to.be.instanceof(Function); }); it('should return the set state', () => { store.setState({name: 'Mark'}); expect(store.getState()).to.deep.equal({name: 'Mark'}); }); }); describe('inheritance', () => { it('should be able to create a functional subclass', () => { class UserStore extends Store { } const userStore = new UserStore({name: 'Mark', userName: 'markpo'}); return eventually(() => { expect(userStore).to.be.instanceof(Store); expect(userStore.state).to.deep.equal({name: 'Mark', userName: 'markpo'}); }); }); }); describe('observable methods', () => { it('should work as expected', (done) => { new Store({name: 'Mark'}) .subscribe((value) => { expect(value).to.deep.equal({name: 'Mark'}); done(); }); }); it('should throttle the output', () => { store = Store.create(); const xs = testScheduler.createHotObservable( onNext(150, 'John'), onNext(210, 'Mark'), onNext(220, 'Jim') ); const results = testScheduler.startScheduler(() => { return xs .flatMap((v) => { store.setState({name: v}); return store; }) .throttle(200, testScheduler); }); expect(results.messages).to.deep.equal([onNext(210, {name: 'Mark'})]); }); it('should still receive replayed values', (done) => { store = new Store({name: 'Mark'}); store.setState({name: 'John'}); store.subscribe((value) => { expect(value).to.deep.equal({name: 'John'}); done(); }); }); it('should not call completed', () => { const completedSpy = spy(); store = new Store({name: 'Mark'}); store.setState({name: 'John'}); store.subscribe(() => {}, () => {}, completedSpy); expect(completedSpy).not.to.be.called; }); }); describe('setSource()', () => { it('should be a method', () => { expect(store.setSource).to.be.instanceof(Function); }); it('should call setState with the result of the passed Observable', () => { spy(store, 'setState'); store.setSource(Observable.return({name: 'John'})); expect(store.setState).to.be.called; }); it('should emit an error when the source emits an error', (done) => { spy(store, 'setState'); store.setSource(Observable.throw('Failed to load')); expect(store.setState).not.to.be.called; store.subscribe(() => { }, (error) => { expect(error).to.equal('Rethrown error from source: Failed to load'); done(); }); }); }); describe('create()', () => { it('should create a store object', () => { expect(Store.create()).to.be.instanceof(Store); }); it('should have initialzed the Store with the value of geInitialState', () => { store = Store.create({ getInitialState() { return {name: 'Mark'}; }, }); store.subscribe(value => { expect(value).to.deep.equal({name: 'Mark'}); }); }); it('should add the passed methods onto the created object', () => { store = Store.create({ getInitialState() { return {name: 'Mark'}; }, getMyCustomValue() { }, }); expect(store.getMyCustomValue).to.be.instanceof(Function); }); it('should not add getInitialState to the result object', () => { store = Store.create({ getInitialState() { return {name: 'Mark'}; }, getMyCustomValue() { }, }); expect(store.getInitialState).to.be.undefined; }); it('should copy properties from the object onto the created object', () => { store = Store.create({ name: 'MyStore', getMyCustomValue() { }, }); expect(store.name).to.equal('MyStore'); }); }); });