Skip to content

Commit 178c043

Browse files
committed
test(sources): add and refine Swap source unit tests; cover default replacement and remove duplicates; fix swap JSDoc (closes #33)
1 parent f4bb38c commit 178c043

File tree

2 files changed

+166
-8
lines changed

2 files changed

+166
-8
lines changed

src/sources/swap-source.test.ts

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
import type { Observable } from 'rxjs';
2+
3+
import { Subject } from 'rxjs';
4+
import { Swap, swap } from './swap-source';
5+
import { MockElement, MockEvent } from '../test-support';
6+
7+
describe('Swap Event Adapter', () => {
8+
it('Swaps a value from an element with a static string', () => {
9+
const oldValue = 'old data';
10+
const newValue = 'new data';
11+
const el = MockElement({
12+
tagName: "INPUT",
13+
type: 'text',
14+
value: oldValue,
15+
});
16+
const eventData = MockEvent('input', {
17+
target: el as HTMLInputElement
18+
});
19+
const handlerSpy = jest.fn();
20+
const source = Swap(newValue, handlerSpy);
21+
22+
source.next(eventData);
23+
24+
expect(handlerSpy).toHaveBeenCalledWith(oldValue);
25+
expect(el.value).toEqual(newValue);
26+
})
27+
})
28+
29+
it('Swaps a value from an element with empty string by default', () => {
30+
const oldValue = 'old data';
31+
const el = MockElement({
32+
tagName: 'INPUT',
33+
type: 'text',
34+
value: oldValue,
35+
});
36+
const eventData = MockEvent('input', {
37+
target: el as HTMLInputElement
38+
});
39+
const handlerSpy = jest.fn();
40+
const source = Swap(undefined, handlerSpy);
41+
42+
source.next(eventData);
43+
44+
expect(handlerSpy).toHaveBeenCalledWith(oldValue);
45+
expect(el.value).toEqual('');
46+
});
47+
48+
it('Swaps a value using a function that transforms based on the old value', () => {
49+
const oldValue = '5';
50+
const replacementFn = (v: string) => String(Number(v) * 2);
51+
const el = MockElement({
52+
tagName: 'INPUT',
53+
type: 'text',
54+
value: oldValue,
55+
});
56+
const eventData = MockEvent('input', {
57+
target: el as HTMLInputElement
58+
});
59+
const handlerSpy = jest.fn();
60+
const source = Swap(replacementFn, handlerSpy);
61+
62+
source.next(eventData);
63+
64+
expect(handlerSpy).toHaveBeenCalledWith(oldValue);
65+
expect(el.value).toEqual('10');
66+
});
67+
68+
describe('swap Event Operator', () => {
69+
it('Swaps and emits a value from an element with a static string', () => {
70+
const oldValue = 'old data';
71+
const newValue = 'new data';
72+
const el = MockElement({
73+
tagName: 'INPUT',
74+
type: 'text',
75+
value: oldValue,
76+
});
77+
const eventData = MockEvent('input', {
78+
target: el as HTMLInputElement
79+
});
80+
const handlerSpy = jest.fn();
81+
const pipeline = new Subject<typeof eventData>().pipe(swap(newValue)) as Observable<string> & Subject<typeof eventData>;
82+
83+
pipeline.subscribe(x => handlerSpy(x));
84+
pipeline.next(eventData);
85+
86+
expect(handlerSpy).toHaveBeenCalledWith(oldValue);
87+
expect(el.value).toEqual(newValue);
88+
});
89+
90+
it('Swaps and emits a value from an element with empty string', () => {
91+
const oldValue = 'old data';
92+
const el = MockElement({
93+
tagName: 'INPUT',
94+
type: 'text',
95+
value: oldValue,
96+
});
97+
const eventData = MockEvent('input', {
98+
target: el as HTMLInputElement
99+
});
100+
const handlerSpy = jest.fn();
101+
const pipeline = new Subject<typeof eventData>().pipe(swap('')) as Observable<string> & Subject<typeof eventData>;
102+
103+
pipeline.subscribe(x => handlerSpy(x));
104+
pipeline.next(eventData);
105+
106+
expect(handlerSpy).toHaveBeenCalledWith(oldValue);
107+
expect(el.value).toEqual('');
108+
});
109+
110+
111+
112+
it('Swaps a value using a function that generates new value from old', () => {
113+
const oldValue = 'test';
114+
const replacementFn = (v: string) => `${v}_modified`;
115+
const el = MockElement({
116+
tagName: 'INPUT',
117+
type: 'text',
118+
value: oldValue,
119+
});
120+
const eventData = MockEvent('input', {
121+
target: el as HTMLInputElement
122+
});
123+
const handlerSpy = jest.fn();
124+
const pipeline = new Subject<typeof eventData>().pipe(swap(replacementFn)) as Observable<string> & Subject<typeof eventData>;
125+
126+
pipeline.subscribe(x => handlerSpy(x));
127+
pipeline.next(eventData);
128+
129+
expect(handlerSpy).toHaveBeenCalledWith(oldValue);
130+
expect(el.value).toEqual('test_modified');
131+
});
132+
133+
it('Handles multiple swap operations in sequence', () => {
134+
const values = ['first', 'second', 'third'];
135+
const el = MockElement({
136+
tagName: 'INPUT',
137+
type: 'text',
138+
value: values[0],
139+
});
140+
const handlerSpy = jest.fn();
141+
const pipeline = new Subject<Event>().pipe(swap('replacement')) as Observable<string> & Subject<Event>;
142+
143+
pipeline.subscribe(x => handlerSpy(x));
144+
145+
values.forEach(val => {
146+
el.value = val;
147+
const eventData = MockEvent('input', { target: el as HTMLInputElement });
148+
pipeline.next(eventData);
149+
});
150+
151+
expect(handlerSpy).toHaveBeenCalledTimes(3);
152+
expect(handlerSpy).toHaveBeenNthCalledWith(1, 'first');
153+
expect(handlerSpy).toHaveBeenNthCalledWith(2, 'second');
154+
expect(handlerSpy).toHaveBeenNthCalledWith(3, 'third');
155+
expect(el.value).toEqual('replacement');
156+
});
157+
});

src/sources/swap-source.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ import { curry } from '../utils/curry';
77
import { EventListenerFunction } from '../types/dom';
88

99
/**
10-
* An Event Source Operator that "cuts" the value of the underlying <input> element
11-
* and resets it to the provided value or empty otherwise
12-
* @param handler A handler function or observer to send events to
13-
* @returns EventSource<string>
10+
* An Event Operator that swaps the value of the underlying <input> element
11+
* with the provided replacement (or empty string by default) and emits the previous value.
12+
* This operator mutates the element's value as a side effect.
13+
* @param replacement A string or function used to compute the new value
14+
* @returns OperatorFunction<Event, string>
1415
*/
1516
export const swap = <E extends Event>(replacement: string | Function) =>
1617
map((e: E) => {
@@ -22,10 +23,10 @@ export const swap = <E extends Event>(replacement: string | Function) =>
2223
;
2324

2425
/**
25-
* An Event Source that "cuts" the value of the underlying &lt;input&gt; element
26-
* and resets it to the provided value or empty otherwise
27-
* @param replacement A new value to swap the current element's value with
28-
* @param source A handler function or observer to send events to
26+
* An Event Adapter that swaps the value of the underlying &lt;input&gt; element
27+
* with the provided replacement (or empty string by default) and emits the previous value to the given target.
28+
* @param replacement A new value or function to compute the element's next value
29+
* @param source A handler function or observer to send emitted values to
2930
* @returns EventSource<string>
3031
*/
3132
export const Swap =

0 commit comments

Comments
 (0)