Files
clean-architecture-frontend…/tests/support/runtime/determinism.ts
T

70 lines
1.7 KiB
TypeScript

import { vi } from "vitest";
export function createDeterministicClock(start = 0) {
let current = start;
return Object.freeze({
now: () => current,
sleep: async (milliseconds: number, signal?: AbortSignal) => {
if (signal?.aborted) throw new DOMException("aborted", "AbortError");
current += Math.max(0, milliseconds);
},
advance(milliseconds: number) {
current += Math.max(0, milliseconds);
},
});
}
export function createSeededRandom(seed = 1) {
let state = seed >>> 0;
return () => {
state = (state * 1_664_525 + 1_013_904_223) >>> 0;
return state / 0x1_0000_0000;
};
}
export function createControlledScheduler() {
const callbacks: Array<() => void> = [];
return Object.freeze({
callbacks,
setTimeout: vi.fn((callback: () => void) => {
callbacks.push(callback);
return callbacks.length - 1;
}),
clearTimeout: vi.fn(),
runNext() {
callbacks.shift()?.();
},
});
}
export function createRecordingStorage() {
const values = new Map<string, string>();
const operations: Array<
Readonly<{ operation: "get" | "set" | "remove"; key: string }>
> = [];
const storage: Storage = {
getItem(key) {
operations.push({ operation: "get", key });
return values.get(key) ?? null;
},
setItem(key, value) {
operations.push({ operation: "set", key });
values.set(key, value);
},
removeItem(key) {
operations.push({ operation: "remove", key });
values.delete(key);
},
clear() {
values.clear();
},
key(index) {
return [...values.keys()][index] ?? null;
},
get length() {
return values.size;
},
};
return Object.freeze({ storage, operations, values });
}