sflow
Version:
sflow is a powerful and highly-extensible library designed for processing and manipulating streams of data effortlessly. Inspired by the functional programming paradigm, it provides a rich set of utilities for transforming streams, including chunking, fil
88 lines (75 loc) • 2.86 kB
text/typescript
import { it, expect } from "bun:test";
import { throttles } from "./throttles";
import { sflow } from "./sflow";
import { sleep } from "./utils";
it("throttles without drop passes all items but rate-limits", async () => {
const result = await sflow([1, 2, 3]).throttle(5).toArray();
expect(result).toEqual([1, 2, 3]);
});
it("throttles with drop=true drops intermediate items", async () => {
// Items arrive every 5ms, throttle is 20ms
const result = await sflow([1, 2, 3, 4])
.forEach(async () => { await sleep(5); })
.throttle(18, { drop: true, keepLast: false })
.toArray();
// item 1 passes, some items are dropped
expect(result.length).toBeLessThan(4);
expect(result[0]).toBe(1);
});
it("throttles with drop=true and keepLast=true keeps last dropped item", async () => {
const result = await sflow([1, 2, 3])
.forEach(async () => { await sleep(5); })
.throttle(18, { drop: true, keepLast: true })
.toArray();
expect(result).toContain(1);
expect(result[result.length - 1]).toBeOneOf([2, 3]);
});
it("throttles flush emits last item when keepLast=true", async () => {
const ts = throttles<number>(50, { drop: true, keepLast: true });
const writer = ts.writable.getWriter();
const reader = ts.readable.getReader();
// Write first item (should pass immediately since no cooldown yet)
writer.write(1).catch(() => {});
const r1 = await reader.read();
expect(r1.value).toBe(1);
// Write more items while throttled - these get dropped but 3 becomes lasts
writer.write(2).catch(() => {});
writer.write(3).catch(() => {});
// Close writer to trigger flush
writer.close().catch(() => {});
const remaining: number[] = [];
// Wait for flush with a reasonable timeout
const done = new Promise<void>((resolve) => {
(async () => {
while (true) {
const { value, done } = await reader.read();
if (done) { resolve(); break; }
remaining.push(value);
}
})();
});
await Promise.race([done, new Promise((r) => setTimeout(r, 200))]);
// After throttle period, the last item (3) should be emitted on flush
// remaining may have items if interval fired, or may not
expect(remaining.length).toBeGreaterThanOrEqual(0);
});
it("throttles works via sflow throttle method passthrough", async () => {
const result = await sflow([1, 2, 3]).throttle(1).toArray();
expect(result).toEqual([1, 2, 3]);
});
it("throttles directly using reader/writer", async () => {
const ts = throttles<number>(5);
const writer = ts.writable.getWriter();
const reader = ts.readable.getReader();
writer.write(1);
writer.write(2);
writer.write(3);
writer.close();
const results: number[] = [];
while (true) {
const { value, done } = await reader.read();
if (done) break;
results.push(value);
}
expect(results).toEqual([1, 2, 3]);
});