Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 113 additions & 64 deletions src/sources/swap-source.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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);
Expand Down Expand Up @@ -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<typeof eventData>().pipe(swap(newValue)) as Observable<string> & Subject<typeof eventData>;
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<typeof eventData>().pipe(swap(replaceFn)) as Observable<string> & Subject<typeof eventData>;
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<typeof eventData>().pipe(swap(newValue)) as Observable<string> & Subject<typeof eventData>;

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<typeof eventData>().pipe(swap('')) as Observable<string> & Subject<typeof eventData>;

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<typeof eventData>().pipe(swap(replacementFn)) as Observable<string> & Subject<typeof eventData>;

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<Event>().pipe(swap('replacement')) as Observable<string> & Subject<Event>;

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');
});
});

});
17 changes: 9 additions & 8 deletions src/sources/swap-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 <input> element
* and resets it to the provided value or empty otherwise
* @param handler A handler function or observer to send events to
* @returns EventSource<string>
* An Event Operator that swaps the value of the underlying <input> 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<Event, string>
*/
export const swap = <E extends Event>(replacement: string | Function) =>
map((e: E) => {
Expand All @@ -22,10 +23,10 @@ export const swap = <E extends Event>(replacement: string | Function) =>
;

/**
* An Event Source that "cuts" the value of the underlying &lt;input&gt; 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 &lt;input&gt; 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<string>
*/
export const Swap =
Expand Down