62 lines
1.9 KiB
TypeScript
62 lines
1.9 KiB
TypeScript
import { describe, expect, it, vi } from "vitest";
|
|
|
|
import { createExponentialBackoff } from "./backoff";
|
|
|
|
describe("createExponentialBackoff", () => {
|
|
it("increments attempt and clamps delay", () => {
|
|
vi.spyOn(Math, "random").mockReturnValue(0);
|
|
|
|
const backoff = createExponentialBackoff({
|
|
baseMs: 100,
|
|
factor: 2,
|
|
maxMs: 250,
|
|
jitter: 0,
|
|
});
|
|
|
|
expect(backoff.attempt()).toBe(0);
|
|
expect(backoff.nextDelayMs()).toBe(100);
|
|
expect(backoff.attempt()).toBe(1);
|
|
expect(backoff.nextDelayMs()).toBe(200);
|
|
expect(backoff.nextDelayMs()).toBe(250); // capped
|
|
});
|
|
|
|
it("clamps invalid numeric options and treats negative jitter as zero", () => {
|
|
vi.spyOn(Math, "random").mockReturnValue(0.9999);
|
|
|
|
// baseMs: NaN should clamp to min (50)
|
|
// maxMs: Infinity should clamp to min (= baseMs)
|
|
// jitter: negative -> treated as 0 (no extra delay)
|
|
const backoff = createExponentialBackoff({
|
|
baseMs: Number.NaN,
|
|
maxMs: Number.POSITIVE_INFINITY,
|
|
jitter: -1,
|
|
});
|
|
|
|
// With maxMs clamped to baseMs, delay will always be baseMs
|
|
expect(backoff.nextDelayMs()).toBe(50);
|
|
expect(backoff.nextDelayMs()).toBe(50);
|
|
});
|
|
|
|
it("reset brings attempt back to zero", () => {
|
|
vi.spyOn(Math, "random").mockReturnValue(0);
|
|
|
|
const backoff = createExponentialBackoff({ baseMs: 100, jitter: 0 });
|
|
backoff.nextDelayMs();
|
|
expect(backoff.attempt()).toBe(1);
|
|
|
|
backoff.reset();
|
|
expect(backoff.attempt()).toBe(0);
|
|
});
|
|
|
|
it("uses defaults when options are omitted", () => {
|
|
vi.spyOn(Math, "random").mockReturnValue(0);
|
|
|
|
const backoff = createExponentialBackoff();
|
|
expect(backoff.attempt()).toBe(0);
|
|
|
|
// Default baseMs is 1000 (clamped within bounds), jitter default is 0.2.
|
|
// With Math.random=0, delay should be the normalized base (1000).
|
|
expect(backoff.nextDelayMs()).toBe(1000);
|
|
});
|
|
});
|