diff --git a/src/sources/swap-source.test.ts b/src/sources/swap-source.test.ts index 2cbfefd..2dfa766 100644 --- a/src/sources/swap-source.test.ts +++ b/src/sources/swap-source.test.ts @@ -6,27 +6,28 @@ import { Swap, swap } from './swap-source'; describe('Swap Event Adapter', () => { - it('Swaps a value in an element with a static string', () => { - const oldValue = 'old data'; - const newValue = 'new data'; + it('Swaps a value from an element with a static string', () => { + const oldValue = 'old data'; + const newValue = 'new data'; - const el = MockElement({ + const el = MockElement({ tagName: 'INPUT', - type: 'text', - value: oldValue, - }); + type: 'text', + value: oldValue, + }); - const eventData = MockEvent('input', { - target: el as HTMLInputElement - }); + const eventData = MockEvent('input', { + target: el as HTMLInputElement + }); - const handlerSpy = jest.fn(); - const source = Swap(newValue)(handlerSpy); - source.next(eventData); + const handlerSpy = jest.fn(); + const source = Swap(newValue, handlerSpy); - expect(handlerSpy).toHaveBeenCalledWith(oldValue); - expect(el.value).toEqual(newValue); - }); + source.next(eventData); + + expect(handlerSpy).toHaveBeenCalledWith(oldValue); + expect(el.value).toEqual(newValue); + }) it('Swaps a value in an element using a function', () => { const oldValue = 'old data'; @@ -44,7 +45,8 @@ describe('Swap Event Adapter', () => { const replaceFn = (v: string) => v.toUpperCase(); const handlerSpy = jest.fn(); - const source = Swap(replaceFn)(handlerSpy); + const source = Swap(undefined, handlerSpy); + source.next(eventData); expect(handlerSpy).toHaveBeenCalledWith(oldValue); @@ -76,51 +78,98 @@ describe('Swap Event Adapter', () => { describe('swap Event Operator', () => { - it('Swaps and emits a value from an element with static string', () => { - const oldValue = 'old data'; - const newValue = 'new data'; - - const el = MockElement({ - tagName: 'INPUT', - type: 'text', - value: oldValue, - }); - - const eventData = MockEvent('input', { - target: el as HTMLInputElement - }); - - const handlerSpy = jest.fn(); - const pipeline = new Subject().pipe(swap(newValue)) as Observable & Subject; - pipeline.subscribe(x => handlerSpy(x)); - pipeline.next(eventData); - - expect(handlerSpy).toHaveBeenCalledWith(oldValue); - expect(el.value).toEqual(newValue); - }); - - it('Swaps and emits a value from an element using function', () => { - const oldValue = 'old data'; - - const el = MockElement({ - tagName: 'INPUT', - type: 'text', - value: oldValue, - }); - - const eventData = MockEvent('input', { - target: el as HTMLInputElement - }); - - const replaceFn = (v: string) => v.toUpperCase(); - - const handlerSpy = jest.fn(); - const pipeline = new Subject().pipe(swap(replaceFn)) as Observable & Subject; - pipeline.subscribe(x => handlerSpy(x)); - pipeline.next(eventData); - - expect(handlerSpy).toHaveBeenCalledWith(oldValue); - expect(el.value).toEqual('OLD DATA'); - }); + it('Swaps and emits a value from an element with a static string', () => { + const oldValue = 'old data'; + const newValue = 'new data'; + + const el = MockElement({ + tagName: 'INPUT', + type: 'text', + value: oldValue, + }); + + const eventData = MockEvent('input', { + target: el as HTMLInputElement + }); + + const handlerSpy = jest.fn(); + const pipeline = new Subject().pipe(swap(newValue)) as Observable & Subject; + + pipeline.subscribe(x => handlerSpy(x)); + pipeline.next(eventData); + + expect(handlerSpy).toHaveBeenCalledWith(oldValue); + expect(el.value).toEqual(newValue); + }); + + it('Swaps and emits a value from an element with empty string', () => { + const oldValue = 'old data'; + + const el = MockElement({ + tagName: 'INPUT', + type: 'text', + value: oldValue, + }); + + const eventData = MockEvent('input', { + target: el as HTMLInputElement + }); + const handlerSpy = jest.fn(); + const pipeline = new Subject().pipe(swap('')) as Observable & Subject; + + pipeline.subscribe(x => handlerSpy(x)); + pipeline.next(eventData); + + expect(handlerSpy).toHaveBeenCalledWith(oldValue); + expect(el.value).toEqual(''); + }); + + + + it('Swaps a value using a function that generates new value from old', () => { + const oldValue = 'test'; + const replacementFn = (v: string) => `${v}_modified`; + const el = MockElement({ + tagName: 'INPUT', + type: 'text', + value: oldValue, + }); + const eventData = MockEvent('input', { + target: el as HTMLInputElement + }); + const handlerSpy = jest.fn(); + const pipeline = new Subject().pipe(swap(replacementFn)) as Observable & Subject; + + pipeline.subscribe(x => handlerSpy(x)); + pipeline.next(eventData); + + expect(handlerSpy).toHaveBeenCalledWith(oldValue); + expect(el.value).toEqual('test_modified'); + }); + + it('Handles multiple swap operations in sequence', () => { + const values = ['first', 'second', 'third']; + const el = MockElement({ + tagName: 'INPUT', + type: 'text', + value: values[0], + }); + const handlerSpy = jest.fn(); + const pipeline = new Subject().pipe(swap('replacement')) as Observable & Subject; + + pipeline.subscribe(x => handlerSpy(x)); + + values.forEach(val => { + el.value = val; + const eventData = MockEvent('input', { target: el as HTMLInputElement }); + pipeline.next(eventData); + }); + + expect(handlerSpy).toHaveBeenCalledTimes(3); + expect(handlerSpy).toHaveBeenNthCalledWith(1, 'first'); + expect(handlerSpy).toHaveBeenNthCalledWith(2, 'second'); + expect(handlerSpy).toHaveBeenNthCalledWith(3, 'third'); + expect(el.value).toEqual('replacement'); + }); +}); -}); \ No newline at end of file diff --git a/src/sources/swap-source.ts b/src/sources/swap-source.ts index 39615ee..90d1abd 100644 --- a/src/sources/swap-source.ts +++ b/src/sources/swap-source.ts @@ -7,10 +7,11 @@ import { curry } from '../utils/curry'; import { EventListenerFunction } from '../types/dom'; /** - * An Event Source Operator that "cuts" the value of the underlying element - * and resets it to the provided value or empty otherwise - * @param handler A handler function or observer to send events to - * @returns EventSource + * An Event Operator that swaps the value of the underlying element + * with the provided replacement (or empty string by default) and emits the previous value. + * This operator mutates the element's value as a side effect. + * @param replacement A string or function used to compute the new value + * @returns OperatorFunction */ export const swap = (replacement: string | Function) => map((e: E) => { @@ -22,10 +23,10 @@ export const swap = (replacement: string | Function) => ; /** - * An Event Source that "cuts" the value of the underlying <input> element - * and resets it to the provided value or empty otherwise - * @param replacement A new value to swap the current element's value with - * @param source A handler function or observer to send events to + * An Event Adapter that swaps the value of the underlying <input> element + * with the provided replacement (or empty string by default) and emits the previous value to the given target. + * @param replacement A new value or function to compute the element's next value + * @param source A handler function or observer to send emitted values to * @returns EventSource */ export const Swap =