rewrite tests with mocked timers

This commit is contained in:
Brent Schroeter 2026-02-06 07:59:19 +00:00
parent d715fabeb5
commit 463b0db759
4 changed files with 49 additions and 28 deletions

View file

@ -8,4 +8,4 @@ module.exports = {
transform: { transform: {
...tsJestTransformCfg, ...tsJestTransformCfg,
}, },
}; };

View file

@ -1,24 +0,0 @@
import { AsyncTaskQueue } from "./index";
test("example evaluates correctly", async () => {
const q = new AsyncTaskQueue<number>(
async () => {/* no-op */},
)
// Handler will receive up to 4 items per batch.
.batchSize(4)
// Handler will be called at most once per 100 milliseconds.
.throttleMs(100);
// Add items to the queue.
for (let n = 0; n < 1000; n++) {
q.push(n);
}
await new Promise((resolve) => setTimeout(resolve, 4000));
expect(q.size()).toBeLessThan(900);
expect(q.size()).toBeGreaterThan(800);
q.drain();
expect(q.size()).toEqual(0);
});

View file

@ -1,4 +1,4 @@
import { withRetry } from "./retries"; import { withRetry } from "../src/retries";
const FAST_RETRY_CONFIG: Parameters<typeof withRetry>[1] = { const FAST_RETRY_CONFIG: Parameters<typeof withRetry>[1] = {
attempts: 6, attempts: 6,
@ -42,6 +42,8 @@ test("parameters are passed through", async () => {
}); });
test("retries back off with expected delays", async () => { test("retries back off with expected delays", async () => {
// Don't enable the `advanceTimers` configuration or else risk skewing the
// timing scheme used in this test.
jest.useFakeTimers(); jest.useFakeTimers();
let n = 0; let n = 0;
@ -93,7 +95,8 @@ test("retries back off with expected delays", async () => {
await expect(promise).resolves.toEqual("success!") await expect(promise).resolves.toEqual("success!")
// Fake timers don't play nicely with the `expect().rejects` API, so disable // Mock timers without auto-advance enabled are a pain to manage when merely
// them again for other tests. // counting retries, so use real timers and a very short backoff duration in
// other tests instead.
jest.useRealTimers(); jest.useRealTimers();
}); });

42
test/task-queue.test.ts Normal file
View file

@ -0,0 +1,42 @@
import { AsyncTaskQueue } from "../src/index";
test("example evaluates correctly", async () => {
jest.useFakeTimers();
const THROTTLE_DELAY_MS = 100;
const q = new AsyncTaskQueue<number>(
async () => {/* no-op */ },
)
// Handler will receive up to 4 items per batch.
.batchSize(4)
// Handler will be called at most once per 100 milliseconds.
.throttleMs(THROTTLE_DELAY_MS);
// Add items to the queue.
for (let n = 0; n < 1000; n++) {
q.push(n);
}
// Advance the clock incrementally and asynchronously so that we yield to the
// task queue control loop frequently. This should allow it to complete its
// work more or less as it would with real timers.
//
// Advance timers by a shorter duration than THROTTLE_DELAY_MS to test that
// the task queue throttles correctly according to wall time and not merely
// according to event loop ticks.
const fakeTimerIncrementMs = Math.ceil(THROTTLE_DELAY_MS / 2);
for (
let mockDelayMs = 0;
mockDelayMs < 4000;
mockDelayMs += fakeTimerIncrementMs
) {
await jest.advanceTimersByTimeAsync(fakeTimerIncrementMs);
}
expect(q.size()).toBeLessThan(850);
expect(q.size()).toBeGreaterThan(825);
q.drain();
expect(q.size()).toEqual(0);
});