import { Window } from 'happy-dom';
import { Cell } from '../reactive';
import { DOMApi } from '../dom-api';
import { Root } from '../dom';

/**
 * Creates a function that tracks how many times it was called.
 * Use this instead of vi.fn() when you only need to verify call counts.
 *
 * @example
 * const { fn, getCallCount } = createCallTracker(() => 42);
 * fn();
 * expect(getCallCount()).toBe(1);
 */
export declare function createCallTracker<T, Args extends unknown[] = []>(implementation: (...args: Args) => T): {
    fn: (...args: Args) => T;
    getCallCount: () => number;
    getLastArgs: () => Args | undefined;
    getAllCalls: () => Args[];
    reset: () => void;
};
/**
 * Creates a getter function that tracks accesses.
 * Useful for testing reactive getter unwrapping.
 *
 * @example
 * const { getter, getAccessCount } = createTrackedGetter(() => 'value');
 * const result = getter();
 * expect(result).toBe('value');
 * expect(getAccessCount()).toBe(1);
 */
export declare function createTrackedGetter<T>(getValue: () => T): {
    getter: () => T;
    getAccessCount: () => number;
    reset: () => void;
};
/**
 * Creates a test Cell with tracking capabilities.
 * Use this when you need a real reactive Cell but want to track updates.
 *
 * @example
 * const { testCell, getUpdateCount } = createTrackedCell(0);
 * testCell.update(1);
 * expect(getUpdateCount()).toBe(1);
 * expect(testCell.value).toBe(1);
 */
export declare function createTrackedCell<T>(initial: T): {
    testCell: Cell<T>;
    getUpdateCount: () => number;
    reset: () => void;
};
/**
 * Creates a regular function (with prototype) for testing.
 * Unlike arrow functions, these should NOT be unwrapped by helpers.
 *
 * @example
 * const callback = createRegularFunction(() => 'result');
 * expect(callback.prototype).toBeDefined(); // Has prototype
 */
export declare function createRegularFunction<T>(implementation: () => T): () => T;
/**
 * Creates a class-based callback for testing.
 * Classes always have prototypes and should not be called as getters.
 */
export declare function createClassCallback<T>(returnValue: T): {
    new (): {};
    getValue(): T;
};
/**
 * Waits for a condition to be true, with timeout.
 * Useful for testing async reactive updates.
 *
 * @example
 * await waitFor(() => element.textContent === 'loaded');
 */
export declare function waitFor(condition: () => boolean, timeout?: number, interval?: number): Promise<void>;
/**
 * Creates a deferred promise for testing async scenarios.
 *
 * @example
 * const { promise, resolve } = createDeferred<string>();
 * // Later...
 * resolve('done');
 * await promise; // 'done'
 */
export declare function createDeferred<T>(): {
    promise: Promise<T>;
    resolve: (value: T) => void;
    reject: (error: Error) => void;
};
/**
 * Flushes microtask queue.
 * Useful for testing reactive updates that use queueMicrotask.
 */
export declare function flushMicrotasks(): Promise<void>;
/**
 * Flushes all pending timers and microtasks.
 */
export declare function flushAll(): Promise<void>;
export interface DOMFixture {
    window: Window;
    document: Document;
    api: DOMApi;
    root: Root;
    container: HTMLElement;
    cleanup: () => void;
}
/**
 * Creates a complete DOM fixture for tests that need happy-dom.
 * Replaces the duplicated beforeEach/afterEach pattern across test files.
 *
 * @param customApi - Optional custom DOMApi to use instead of HTMLBrowserDOMApi
 *
 * @example
 * let fixture: DOMFixture;
 * beforeEach(() => { fixture = createDOMFixture(); });
 * afterEach(() => { fixture.cleanup(); });
 */
export declare function createDOMFixture(customApi?: DOMApi): DOMFixture;
/**
 * Creates a test suspense context that tracks start/end calls.
 * Use this instead of vi.fn() for suspense protocol tests.
 *
 * @example
 * const { ctx, getStartCount, getEndCount } = createTestSuspenseContext();
 * provideContext(component, SUSPENSE_CONTEXT, ctx);
 * // ... trigger followPromise ...
 * expect(getStartCount()).toBe(1);
 */
export declare function createTestSuspenseContext(): {
    ctx: {
        start(): void;
        end(): void;
    };
    getStartCount: () => number;
    getEndCount: () => number;
    reset(): void;
};
