UNPKG

@equinor/fusion-observable

Version:
154 lines (137 loc) 4.64 kB
import { Observable, throwError } from 'rxjs'; import { filter, map, tap, withLatestFrom } from 'rxjs/operators'; import { ReactiveObservable } from '../ReactiveObservable'; import type { Epic } from '../types'; type State = { value: string; index: number }; type Action = { type: string; payload: string }; const createTest = (initial: string) => { const subject = new ReactiveObservable<State, Action>( (state, action) => { return { value: action.payload, index: state.index + 1 }; }, { value: initial, index: 0 }, ); return subject; }; describe('Reactive observable', () => { it('should allow to subscribe', (done) => { const expected = ['initial', 'test']; const subject = createTest(expected[0]); subject.subscribe({ next: (next) => { expect(next.value).toEqual(expected[next.index]); }, complete: () => { expect.assertions(expected.length); done(); }, }); subject.next({ type: 'test', payload: expected[1] }); subject.complete(); }); it('should allow multiple subscriptions', (done) => { const expected = ['initial', 'test']; const subject = createTest(expected[0]); const assert = (state: State) => expect(state.value).toEqual(expected[state.index]); subject.subscribe(assert); subject.subscribe(assert); subject.subscribe(assert); subject.subscribe({ complete: () => { expect.assertions(expected.length * 3); done(); }, }); subject.next({ type: 'test', payload: expected[1] }); subject.complete(); }); it('should unsubscribe', (complete) => { const expected = ['initial', 'test1', 'test2']; const subject = createTest(expected[0]); const cache: State[] = []; subject.subscribe((x) => cache.push(x)); expect(cache).toHaveLength(1); subject.next({ type: 'test', payload: expected[1] }); expect(cache).toHaveLength(2); subject.unsubscribe(); try { subject.next({ type: 'test', payload: expected[2] }); } catch (err) { expect(err).toBeInstanceOf(Error); complete(); } }); it('should failed to add invalid epic', () => { const subject = createTest('test'); const invalidEpic = () => null; try { subject.addEpic(invalidEpic as unknown as Epic<Action, State>); expect(true).toBeFalsy(); } catch (err) { expect(err).toBeInstanceOf(TypeError); } }); it('it should handle epics that fails', () => { const subject = createTest('test'); const epic = () => throwError(() => Error('as expected')); const consoleError = console.error; console.error = jest.fn(); subject.addEpic(epic); subject.next({ type: 'test', payload: '' }); expect(console.error).toBeCalledTimes(1); console.warn = consoleError; }); it('should reset to initial value', () => { const expected = ['initial', 'test']; const subject = createTest(expected[0]); const initial = subject.value; subject.next({ type: 'test', payload: expected[1] }); expect(subject.value.value).toEqual(expected[1]); subject.reset(); expect(subject.value).toEqual(initial); }); it('should convert to observable', () => { const subject = createTest('test'); const observable = subject.asObservable(); expect(observable).toBeInstanceOf(Observable); }); it('should handle side effects', (done) => { const expectedValues = ['initial', 'dispatched', 'effect']; const expectedActions = [ { type: 'dispatch', payload: expectedValues[1] }, { type: 'effect', payload: expectedValues[2] }, ]; const assertState = (state: State) => expect(state.value).toEqual(expectedValues[state.index]); const subject = createTest(expectedValues[0]); subject.subscribe({ next: (state) => { assertState(state); }, complete: () => { done(); }, }); subject.addEpic((action$, state$) => { return action$.pipe( filter((x) => x === expectedActions[0]), withLatestFrom(state$), tap(([action, state]) => { expect(action).toEqual(expectedActions[0]); assertState(state); }), map(() => expectedActions[1]), ); }); const consoleWarn = console.warn; console.warn = jest.fn(); subject.addEffect(expectedActions[0].type, () => { throw Error('Should not bork code!'); }); subject.addEffect('effect', () => { expect(console.warn).toBeCalledTimes(1); console.warn = consoleWarn; subject.complete(); }); subject.next(expectedActions[0]); }); });