UNPKG

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

127 lines (117 loc) 3.28 kB
import { retry } from "./retry"; import { sflow } from "./sflow"; describe("retry", () => { it("returns result on first success", async () => { const fn = retry((_e, _a, fn, x) => fn(x), async (x: number) => x * 2); expect(await fn(5)).toBe(10); }); it("retries on transient errors", async () => { let calls = 0; const fn = retry( (_error, attempt, fn) => { if (attempt > 5) throw _error; return fn(); }, async () => { calls++; if (calls < 3) throw new Error("transient"); return "ok"; }, ); expect(await fn()).toBe("ok"); expect(calls).toBe(3); }); it("stops retrying when handler throws", async () => { let calls = 0; const fn = retry( (error) => { throw error; }, async () => { calls++; throw new Error("permanent"); }, ); await expect(fn()).rejects.toThrow("permanent"); expect(calls).toBe(1); }); it("passes attempt count correctly (1-based)", async () => { const attempts: number[] = []; let calls = 0; const fn = retry( (_error, attempt, fn) => { attempts.push(attempt); if (attempt >= 3) throw new Error("give up"); return fn(); }, async () => { calls++; throw new Error("fail"); }, ); await expect(fn()).rejects.toThrow("give up"); expect(attempts).toEqual([1, 2, 3]); expect(calls).toBe(3); }); it("passes original args to error handler", async () => { const receivedArgs: [string, number][] = []; let calls = 0; const fn = retry( (_error, _attempt, fn, a, b) => { receivedArgs.push([a, b]); if (calls >= 2) throw new Error("stop"); return fn(a, b); }, async (_a: string, _b: number) => { calls++; throw new Error("fail"); }, ); await expect(fn("hello", 42)).rejects.toThrow("stop"); expect(receivedArgs[0]).toEqual(["hello", 42]); }); it("works with sync functions", async () => { let calls = 0; const fn = retry( (_error, attempt, fn, x) => { if (attempt > 5) throw _error; return fn(x); }, (x: number) => { calls++; if (calls < 2) throw new Error("transient"); return x + 1; }, ); expect(await fn(10)).toBe(11); expect(calls).toBe(2); }); it("retries with different args", async () => { const fn = retry( (error, attempt, fn, x) => { if (attempt > 5) throw error; return fn(x + 1); }, async (x: number) => { if (x < 5) throw new Error("too small"); return x; }, ); expect(await fn(3)).toBe(5); }); it("works inside sflow().map()", async () => { const callCounts = new Map<number, number>(); const fn = retry( (error, attempt, fn, x) => { if (attempt > 2) throw error; return fn(x); }, async (x: number) => { const count = (callCounts.get(x) ?? 0) + 1; callCounts.set(x, count); if (x === 2 && count < 2) throw new Error("transient"); return x * 10; }, ); const result = await sflow([1, 2, 3]).map(fn).toArray(); expect(result).toEqual([10, 20, 30]); }); });