import type { MaybePromise } from "core/types"; export type Matcher = { toEqual: (expected: T, failMsg?: string) => void; toBe: (expected: T, failMsg?: string) => void; toBeUndefined: (failMsg?: string) => void; toBeString: (failMsg?: string) => void; toBeOneOf: (expected: T | Array | Iterable, failMsg?: string) => void; toBeDefined: (failMsg?: string) => void; toHaveBeenCalled: (failMsg?: string) => void; toHaveBeenCalledTimes: (expected: number, failMsg?: string) => void; }; export type TestFn = (() => void | Promise) | ((done: (err?: unknown) => void) => void); export interface Test { (label: string, fn: TestFn, options?: any): void; if: (condition: boolean) => (label: string, fn: TestFn, options?: any) => void; skip: (label: string, fn: () => void) => void; skipIf: (condition: boolean) => (label: string, fn: TestFn) => void; } export type TestRunner = { describe: (label: string, asyncFn: () => MaybePromise) => void; test: Test; mock: any>(fn: T) => T | any; expect: ( actual?: T, failMsg?: string, ) => Matcher & { resolves: Matcher>; rejects: Matcher>; }; beforeEach: (fn: () => MaybePromise) => void; afterEach: (fn: () => MaybePromise) => void; afterAll: (fn: () => MaybePromise) => void; }; export async function retry( fn: () => Promise, condition: (result: T) => boolean, retries: number, delay: number, ): Promise { let lastError: Error | null = null; for (let i = 0; i < retries; i++) { try { const result = await fn(); if (condition(result)) { return result; } else { await new Promise((resolve) => setTimeout(resolve, delay)); } } catch (error) { lastError = error as Error; await new Promise((resolve) => setTimeout(resolve, delay)); } } throw lastError; }