···11+import { it, expect, vi } from 'vitest';
22+13import { Source, Sink, Operator, Signal, SignalKind, TalkbackKind, TalkbackFn } from '../types';
24import { push, start } from '../helpers';
35···41434244 // When pulling a value we expect an immediate response
4345 talkback!(TalkbackKind.Pull);
4444- jest.runAllTimers();
4646+ vi.runAllTimers();
4547 expect(values).toEqual([output]);
4648 });
4749};
···82848385 // When pushing a value we expect an immediate response
8486 sink!(push(0));
8585- jest.runAllTimers();
8787+ vi.runAllTimers();
8688 expect(values).toEqual([result]);
8789 // Subsequently the Pull signal should have travelled upwards
8890 expect(pulls).toBe(1);
···124126125127 // When pushing a value we expect an immediate close signal
126128 talkback!(TalkbackKind.Pull);
127127- jest.runAllTimers();
129129+ vi.runAllTimers();
128130 expect(closing).toBe(1);
129131 });
130132};
···170172171173 // When pushing a value we expect an immediate Push then End signal
172174 talkback!(TalkbackKind.Pull);
173173- jest.runAllTimers();
175175+ vi.runAllTimers();
174176 expect(ending).toBe(1);
175177 expect(signals).toEqual([push(result), SignalKind.End]);
176178 // Also no additional pull event should be created by the operator
···221223222224 // When pushing a value we expect an immediate Push then End signal
223225 talkback!(TalkbackKind.Pull);
224224- jest.runAllTimers();
226226+ vi.runAllTimers();
225227 expect(ending).toBe(1);
226228 expect(pulls).toBe(3);
227229 expect(signals).toEqual([push(result), push(result), SignalKind.End]);
···288290 operator(source)(sink);
289291290292 // The Push signal should've been dropped
291291- jest.runAllTimers();
293293+ vi.runAllTimers();
292294 expect(signals).toEqual([SignalKind.End]);
293295 expect(pulls).toBe(1);
294296 });
···319321 operator(source)(sink);
320322321323 // The Push signal should've been dropped
322322- jest.runAllTimers();
324324+ vi.runAllTimers();
323325 expect(signals).toEqual([]);
324326 });
325327};
···395397 // Afterwards after all timers all other signals come in
396398 operator(source)(sink);
397399 expect(signals.length).toBe(0);
398398- jest.advanceTimersByTime(5);
400400+ vi.advanceTimersByTime(5);
399401 expect(hasPushed).toBeTruthy();
400400- jest.runAllTimers();
402402+ vi.runAllTimers();
401403402404 expect(signals).toEqual([push(result), SignalKind.End]);
403405 });
+45-43
src/__tests__/operators.test.ts
···11+import { describe, it, expect, beforeEach, vi } from 'vitest';
22+13import { Source, Sink, Signal, SignalKind, TalkbackKind, TalkbackFn } from '../types';
24import { push, start } from '../helpers';
35···1820import * as operators from '../operators';
19212022beforeEach(() => {
2121- jest.useFakeTimers();
2323+ vi.useFakeTimers();
2224});
23252426describe('buffer', () => {
···4143 it('emits batches of input values when a notifier emits', () => {
4244 const { source: notifier$, next: notify } = sources.makeSubject();
4345 const { source: input$, next } = sources.makeSubject();
4444- const fn = jest.fn();
4646+ const fn = vi.fn();
45474648 sinks.forEach(fn)(operators.buffer(notifier$)(input$));
4749···7173 // This synchronous test for concatMap will behave the same as mergeMap & switchMap
7274 it('emits values from each flattened synchronous source', () => {
7375 const { source, next, complete } = sources.makeSubject<number>();
7474- const fn = jest.fn();
7676+ const fn = vi.fn();
75777678 operators.concatMap((x: number) => sources.fromArray([x, x + 1]))(source)(fn);
7779···9395 // This synchronous test for concatMap will behave the same as mergeMap & switchMap
9496 it('lets inner sources finish when outer source ends', () => {
9597 const signals: Signal<any>[] = [];
9696- const teardown = jest.fn();
9898+ const teardown = vi.fn();
9799 const fn = (signal: Signal<any>) => {
98100 signals.push(signal);
99101 if (signal !== SignalKind.End && signal.tag === SignalKind.Start) {
···113115 // This asynchronous test for concatMap will behave differently than mergeMap & switchMap
114116 it('emits values from each flattened asynchronous source, one at a time', () => {
115117 const source = operators.delay<number>(4)(sources.fromArray([1, 10]));
116116- const fn = jest.fn();
118118+ const fn = vi.fn();
117119118120 sinks.forEach(fn)(
119121 operators.concatMap((x: number) => {
···121123 })(source)
122124 );
123125124124- jest.advanceTimersByTime(14);
126126+ vi.advanceTimersByTime(14);
125127 expect(fn.mock.calls).toEqual([[1], [2]]);
126128127127- jest.runAllTimers();
129129+ vi.runAllTimers();
128130 expect(fn.mock.calls).toEqual([[1], [2], [10], [20]]);
129131 });
130132131133 it('works for fully asynchronous sources', () => {
132132- const fn = jest.fn();
134134+ const fn = vi.fn();
133135134136 sinks.forEach(fn)(
135137 operators.concatMap(() => {
···140142 })(sources.fromValue(null))
141143 );
142144143143- jest.runAllTimers();
145145+ vi.runAllTimers();
144146 expect(fn).toHaveBeenCalledWith(1);
145147 });
146148···167169168170 it('waits for a specified amount of silence before emitting the last value', () => {
169171 const { source, next } = sources.makeSubject<number>();
170170- const fn = jest.fn();
172172+ const fn = vi.fn();
171173172174 sinks.forEach(fn)(operators.debounce(() => 100)(source));
173175174176 next(1);
175175- jest.advanceTimersByTime(50);
177177+ vi.advanceTimersByTime(50);
176178 expect(fn).not.toHaveBeenCalled();
177179178180 next(2);
179179- jest.advanceTimersByTime(99);
181181+ vi.advanceTimersByTime(99);
180182 expect(fn).not.toHaveBeenCalled();
181183182182- jest.advanceTimersByTime(1);
184184+ vi.advanceTimersByTime(1);
183185 expect(fn).toHaveBeenCalledWith(2);
184186 });
185187186188 it('emits debounced value with delayed End signal', () => {
187189 const { source, next, complete } = sources.makeSubject<number>();
188188- const fn = jest.fn();
190190+ const fn = vi.fn();
189191190192 sinks.forEach(fn)(operators.debounce(() => 100)(source));
191193192194 next(1);
193195 complete();
194194- jest.advanceTimersByTime(100);
196196+ vi.advanceTimersByTime(100);
195197 expect(fn).toHaveBeenCalled();
196198 });
197199});
···207209208210 it('delays outputs by a specified delay timeout value', () => {
209211 const { source, next } = sources.makeSubject();
210210- const fn = jest.fn();
212212+ const fn = vi.fn();
211213212214 sinks.forEach(fn)(operators.delay(100)(source));
213215214216 next(1);
215217 expect(fn).not.toHaveBeenCalled();
216218217217- jest.advanceTimersByTime(100);
219219+ vi.advanceTimersByTime(100);
218220 expect(fn).toHaveBeenCalledWith(1);
219221 });
220222});
···230232231233 it('prevents emissions for which a predicate fails', () => {
232234 const { source, next } = sources.makeSubject();
233233- const fn = jest.fn();
235235+ const fn = vi.fn();
234236235237 sinks.forEach(fn)(operators.filter(x => !!x)(source));
236238···253255254256 it('maps over values given a transform function', () => {
255257 const { source, next } = sources.makeSubject<number>();
256256- const fn = jest.fn();
258258+ const fn = vi.fn();
257259258260 sinks.forEach(fn)(operators.map((x: number) => x + 1)(source));
259261···275277 // This synchronous test for mergeMap will behave the same as concatMap & switchMap
276278 it('emits values from each flattened synchronous source', () => {
277279 const { source, next, complete } = sources.makeSubject<number>();
278278- const fn = jest.fn();
280280+ const fn = vi.fn();
279281280282 operators.mergeMap((x: number) => sources.fromArray([x, x + 1]))(source)(fn);
281283···296298 // This synchronous test for mergeMap will behave the same as concatMap & switchMap
297299 it('lets inner sources finish when outer source ends', () => {
298300 const values: Signal<any>[] = [];
299299- const teardown = jest.fn();
301301+ const teardown = vi.fn();
300302 const fn = (signal: Signal<any>) => {
301303 values.push(signal);
302304 if (signal !== SignalKind.End && signal.tag === SignalKind.Start) {
···316318 // This asynchronous test for mergeMap will behave differently than concatMap & switchMap
317319 it('emits values from each flattened asynchronous source simultaneously', () => {
318320 const source = operators.delay<number>(4)(sources.fromArray([1, 10]));
319319- const fn = jest.fn();
321321+ const fn = vi.fn();
320322321323 sinks.forEach(fn)(
322324 operators.mergeMap((x: number) => {
···324326 })(source)
325327 );
326328327327- jest.runAllTimers();
329329+ vi.runAllTimers();
328330 expect(fn.mock.calls).toEqual([[1], [10], [2], [20]]);
329331 });
330332···351353352354 it('calls a callback when the source ends', () => {
353355 const { source, next, complete } = sources.makeSubject<any>();
354354- const fn = jest.fn();
356356+ const fn = vi.fn();
355357356358 sinks.forEach(() => {})(operators.onEnd(fn)(source));
357359···375377376378 it('calls a callback when the source emits', () => {
377379 const { source, next } = sources.makeSubject<number>();
378378- const fn = jest.fn();
380380+ const fn = vi.fn();
379381380382 sinks.forEach(() => {})(operators.onPush(fn)(source));
381383···402404 it('is called when the source starts', () => {
403405 let sink: Sink<any>;
404406405405- const fn = jest.fn();
407407+ const fn = vi.fn();
406408 const source: Source<any> = _sink => {
407409 sink = _sink;
408410 };
···436438 it('emits the latest value when a notifier source emits', () => {
437439 const { source: notifier$, next: notify } = sources.makeSubject();
438440 const { source: input$, next } = sources.makeSubject();
439439- const fn = jest.fn();
441441+ const fn = vi.fn();
440442441443 sinks.forEach(fn)(operators.sample(notifier$)(input$));
442444···460462461463 it('folds values continuously with a reducer and initial value', () => {
462464 const { source: input$, next } = sources.makeSubject<number>();
463463- const fn = jest.fn();
465465+ const fn = vi.fn();
464466465467 const reducer = (acc: number, x: number) => acc + x;
466468 sinks.forEach(fn)(operators.scan(reducer, 0)(input$));
···493495 };
494496 });
495497496496- const fnA = jest.fn();
497497- const fnB = jest.fn();
498498+ const fnA = vi.fn();
499499+ const fnB = vi.fn();
498500499501 sinks.forEach(fnA)(source);
500502 sinks.forEach(fnB)(source);
···517519518520 it('skips a number of values before emitting normally', () => {
519521 const { source, next } = sources.makeSubject<number>();
520520- const fn = jest.fn();
522522+ const fn = vi.fn();
521523522524 sinks.forEach(fn)(operators.skip(1)(source));
523525···541543 it('skips values until the notifier source emits', () => {
542544 const { source: notifier$, next: notify } = sources.makeSubject();
543545 const { source: input$, next } = sources.makeSubject<number>();
544544- const fn = jest.fn();
546546+ const fn = vi.fn();
545547546548 sinks.forEach(fn)(operators.skipUntil(notifier$)(input$));
547549···564566565567 it('skips values until one fails a predicate', () => {
566568 const { source, next } = sources.makeSubject<number>();
567567- const fn = jest.fn();
569569+ const fn = vi.fn();
568570569571 sinks.forEach(fn)(operators.skipWhile((x: any) => x <= 1)(source));
570572···588590 // This synchronous test for switchMap will behave the same as concatMap & mergeMap
589591 it('emits values from each flattened synchronous source', () => {
590592 const { source, next, complete } = sources.makeSubject<number>();
591591- const fn = jest.fn();
593593+ const fn = vi.fn();
592594593595 operators.switchMap((x: number) => sources.fromArray([x, x + 1]))(source)(fn);
594596···610612 // This synchronous test for switchMap will behave the same as concatMap & mergeMap
611613 it('lets inner sources finish when outer source ends', () => {
612614 const signals: Signal<any>[] = [];
613613- const teardown = jest.fn();
615615+ const teardown = vi.fn();
614616 const fn = (signal: Signal<any>) => {
615617 signals.push(signal);
616618 if (signal !== SignalKind.End && signal.tag === SignalKind.Start) {
···630632 // This asynchronous test for switchMap will behave differently than concatMap & mergeMap
631633 it('emits values from each flattened asynchronous source, one at a time', () => {
632634 const source = operators.delay<number>(4)(sources.fromArray([1, 10]));
633633- const fn = jest.fn();
635635+ const fn = vi.fn();
634636635637 sinks.forEach(fn)(
636638 operators.switchMap((x: number) =>
···638640 )(source)
639641 );
640642641641- jest.runAllTimers();
643643+ vi.runAllTimers();
642644 expect(fn.mock.calls).toEqual([[1], [10], [20]]);
643645 });
644646});
···657659658660 it('emits values until a maximum is reached', () => {
659661 const { source, next } = sources.makeSubject<number>();
660660- const fn = jest.fn();
662662+ const fn = vi.fn();
661663662664 operators.take(1)(source)(fn);
663665 next(1);
···683685 it('emits values until a notifier emits', () => {
684686 const { source: notifier$, next: notify } = sources.makeSubject<any>();
685687 const { source: input$, next } = sources.makeSubject<number>();
686686- const fn = jest.fn();
688688+ const fn = vi.fn();
687689688690 operators.takeUntil(notifier$)(input$)(fn);
689691 next(1);
···711713712714 it('emits values while a predicate passes for all values', () => {
713715 const { source, next } = sources.makeSubject<number>();
714714- const fn = jest.fn();
716716+ const fn = vi.fn();
715717716718 operators.takeWhile((x: any) => x < 2)(source)(fn);
717719 next(1);
···762764763765 it('should ignore emissions for a period of time after a value', () => {
764766 const { source, next } = sources.makeSubject<number>();
765765- const fn = jest.fn();
767767+ const fn = vi.fn();
766768767769 sinks.forEach(fn)(operators.throttle(() => 100)(source));
768770769771 next(1);
770772 expect(fn).toHaveBeenCalledWith(1);
771771- jest.advanceTimersByTime(50);
773773+ vi.advanceTimersByTime(50);
772774773775 next(2);
774776 expect(fn).toHaveBeenCalledTimes(1);
775775- jest.advanceTimersByTime(50);
777777+ vi.advanceTimersByTime(50);
776778777779 next(3);
778780 expect(fn).toHaveBeenCalledWith(3);