UNPKG

@idiosync/react-observable

Version:

State management control layer for React projects

231 lines (230 loc) 10.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const create_command_stream_1 = require("./create-command-stream"); const observable_1 = require("./observable"); describe('createCommandStream', () => { describe('Basic functionality', () => { it('should create a command stream function', () => { const command = (0, create_command_stream_1.createCommandStream)(({ $, store }) => { return $.stream((value) => value); }); expect(typeof command).toBe('function'); expect(command.exit$).toBeDefined(); }); it('should execute and return a promise', async () => { const command = (0, create_command_stream_1.createCommandStream)(({ $, store }) => { return $.stream((value) => value); }); const result = command('test'); expect(result).toBeInstanceOf(Promise); const [data, error] = await result; expect(data).toBe('test'); expect(error).toBeUndefined(); }); it('should handle async operations', async () => { const command = (0, create_command_stream_1.createCommandStream)(({ $, store }) => { return $.streamAsync(async (value) => { await new Promise((resolve) => setTimeout(resolve, 10)); return value + ' processed'; }); }); const [data, error] = await command('test'); expect(data).toBe('test processed'); expect(error).toBeUndefined(); }); }); describe('Error handling', () => { it('should handle errors in stream', async () => { const command = (0, create_command_stream_1.createCommandStream)(({ $, store }) => { return $.streamAsync(async (value) => { throw new Error('Test error'); }); }); const [data, error] = await command('test'); expect(data).toBeUndefined(); expect(error).toBeInstanceOf(Error); expect(error.message).toBe('Test error'); }); it('should call onError callback when provided', async () => { const onError = jest.fn(); const command = (0, create_command_stream_1.createCommandStream)(({ $, store }) => { return $.streamAsync(async (value) => { throw new Error('Test error'); }); }, { onError }); await command('test'); expect(onError).toHaveBeenCalledWith(expect.any(Error), expect.any(Array)); }); }); describe('Execution tracking', () => { it('should track multiple concurrent executions', async () => { const command = (0, create_command_stream_1.createCommandStream)(({ $, store }) => { return $.streamAsync(async (value) => { await new Promise((resolve) => setTimeout(resolve, 50)); return value; }); }); const execution1 = command('first'); const execution2 = command('second'); const [result1, error1] = await execution1; const [result2, error2] = await execution2; expect(result1).toBe('first'); expect(result2).toBe('second'); expect(error1).toBeUndefined(); expect(error2).toBeUndefined(); }); it('should isolate execution results', async () => { const command = (0, create_command_stream_1.createCommandStream)(({ $, store }) => { return $.stream((value) => value); }); const promise1 = command('value1'); const promise2 = command('value2'); const [data1] = await promise1; const [data2] = await promise2; expect(data1).toBe('value1'); expect(data2).toBe('value2'); }); }); describe('Store integration', () => { it('should provide store to stream', async () => { const mockStore = { test: { value$: (0, observable_1.createObservable)({ initialValue: 'store value' }), }, }; const command = (0, create_command_stream_1.createCommandStream)(({ $, store }) => { return $.stream((value) => { return `${value} - ${store.test.value$.get()}`; }); }); const [data] = await command('input'); expect(data).toBe('input - store value'); }); it('should handle store updates', async () => { const mockStore = { counter: { count$: (0, observable_1.createObservable)({ initialValue: 0 }), }, }; const command = (0, create_command_stream_1.createCommandStream)(({ $, store }) => { return $.stream((value) => { store.counter.count$.set(store.counter.count$.get() + 1); return store.counter.count$.get(); }); }); const [data] = await command('increment'); expect(data).toBe(1); }); }); describe('Exit observable', () => { it('should provide exit observable', () => { const command = (0, create_command_stream_1.createCommandStream)(({ $, store }) => { return $.stream((value) => value); }); expect(command.exit$).toBeDefined(); expect(typeof command.exit$.subscribe).toBe('function'); }); it('should emit results to exit observable', async () => { const command = (0, create_command_stream_1.createCommandStream)(({ $, store }) => { return $.stream((value) => value); }); const listener = jest.fn(); command.exit$.subscribe(listener); await command('test'); expect(listener).toHaveBeenCalledWith('test', expect.any(Array)); }); it('should handle initial value in exit observable', () => { const command = (0, create_command_stream_1.createCommandStream)(({ $, store }) => { return $.stream((value) => value); }, { initialValue: 'initial' }); expect(command.exit$.get()).toBe('initial'); }); }); describe('Result observable integration', () => { it('should integrate with external result observable', async () => { const result$ = (0, observable_1.createObservable)(); const command = (0, create_command_stream_1.createCommandStream)(({ $, store }) => { return $.stream((value) => value); }, { result$ }); await command('test'); expect(result$.get()).toBe('test'); }); }); describe('Stream operations', () => { it('should handle stream with latest from', async () => { const command = (0, create_command_stream_1.createCommandStream)(({ $, store }) => { return $.withLatestFrom((0, observable_1.createObservable)({ initialValue: 'context' })).stream(([value, context]) => `${value} with ${context}`); }); const [data] = await command('input'); expect(data).toBe('input with context'); }); it('should handle combine latest from', async () => { const command = (0, create_command_stream_1.createCommandStream)(({ $, store }) => { return $.combineLatestFrom((0, observable_1.createObservable)({ initialValue: 'a' }), (0, observable_1.createObservable)({ initialValue: 'b' })).stream(([value, a, b]) => `${value}-${a}-${b}`); }); const [data] = await command('input'); expect(data).toBe('input-a-b'); }); it('should handle tap operations', async () => { const sideEffect = jest.fn(); const command = (0, create_command_stream_1.createCommandStream)(({ $, store }) => { return $.tap(sideEffect).stream((value) => value); }); await command('test'); expect(sideEffect).toHaveBeenCalledWith('test'); }); it('should handle catch error operations', async () => { const command = (0, create_command_stream_1.createCommandStream)(({ $, store }) => { return $.streamAsync(async (value) => { throw new Error('Stream error'); }).catchError((error, currentValue, setter) => { setter('recovered'); }); }); const [data, error] = await command('test'); expect(data).toBe('recovered'); expect(error).toBeUndefined(); }); }); describe('Complex scenarios', () => { it('should handle chained operations', async () => { const command = (0, create_command_stream_1.createCommandStream)(({ $, store }) => { return $.stream((value) => value) .stream((value) => value.toUpperCase()) .stream((value) => `${value}!`); }); const [data] = await command('hello'); expect(data).toBe('HELLO!'); }); it('should handle async chained operations', async () => { const command = (0, create_command_stream_1.createCommandStream)(({ $, store }) => { return $.streamAsync(async (value) => { await new Promise((resolve) => setTimeout(resolve, 10)); return value + '1'; }).streamAsync(async (value) => { await new Promise((resolve) => setTimeout(resolve, 10)); return value + '2'; }); }); const [data] = await command('test'); expect(data).toBe('test12'); }); it('should handle store updates in complex scenarios', async () => { const mockStore = { user: { name$: (0, observable_1.createObservable)({ initialValue: 'John' }), age$: (0, observable_1.createObservable)({ initialValue: 25 }), }, }; const command = (0, create_command_stream_1.createCommandStream)(({ $, store }) => { return $.stream((value) => { const name = store.user.name$.get(); const age = store.user.age$.get(); return `${value} by ${name} (${age})`; }); }); const [data] = await command('action'); expect(data).toBe('action by John (25)'); }); }); });