@orchard9ai/testing-utils
Version:
Testing utilities for Orchard9 platform
423 lines (408 loc) • 12.2 kB
TypeScript
import React, { ComponentType, ReactNode, ReactElement } from 'react';
import { RenderOptions, RenderResult } from '@testing-library/react';
export { act, cleanup, fireEvent, screen, waitFor as waitForElement, within } from '@testing-library/react';
import { UserRole, UserStatus, UserProfile, User, AuthenticatedUser, CreateUserInput, ApiResponse, ApiError, ApiErrorResponse, PaginatedResponse, BatchResponse, HealthCheck, HealthCheckResponse } from '@orchard9ai/types';
import * as jest_axe from 'jest-axe';
import axe from 'axe-core';
export { default as userEvent } from '@testing-library/user-event';
/**
* Render configuration types
* @module @orchard9ai/testing-utils/render/types
*/
/**
* Provider configuration
*/
interface ProvidersConfig {
/** Enable/disable theme provider */
theme?: boolean;
/** Theme provider component */
providers?: {
theme?: ComponentType<any>;
router?: ComponentType<any>;
auth?: ComponentType<any>;
i18n?: ComponentType<any>;
};
/** Theme configuration */
themeConfig?: any;
/** Router configuration */
routerConfig?: any;
/** Auth configuration */
authConfig?: any;
/** i18n configuration */
i18nConfig?: any;
/** Router provider */
router?: boolean;
/** Auth provider */
auth?: boolean;
/** i18n provider */
i18n?: boolean;
/** Additional custom providers */
customProviders?: ComponentType<{
children: ReactNode;
}>[];
}
/**
* Custom render functions with providers
* @module @orchard9ai/testing-utils/render
*/
/**
* Default test providers wrapper
*/
declare const createWrapper: (config?: ProvidersConfig) => ({ children }: {
children: ReactNode;
}) => React.FunctionComponentElement<React.FragmentProps>;
/**
* Render with all configured providers
*/
declare function renderWithProviders(ui: ReactElement, options?: RenderOptions & {
providerConfig?: ProvidersConfig;
}): RenderResult;
/**
* Render with default providers
*/
declare function render(ui: ReactElement, options?: RenderOptions): RenderResult;
/**
* Render hook with providers
*/
declare function renderHook<TProps, TResult>(callback: (props: TProps) => TResult, options?: RenderOptions & {
providerConfig?: ProvidersConfig;
initialProps?: TProps;
}): {
result: TResult;
rerender: (props?: TProps) => void;
} & Omit<RenderResult, 'rerender'>;
/**
* User test data builder
* @module @orchard9ai/testing-utils/builders/user
*/
/**
* Base user builder
*/
declare const userBuilder: () => {
withId(id: string): /*elided*/ any;
withEmail(email: string): /*elided*/ any;
withDisplayName(displayName: string): /*elided*/ any;
withRole(role: UserRole): /*elided*/ any;
withStatus(status: UserStatus): /*elided*/ any;
withProfile(profile: Partial<UserProfile>): /*elided*/ any;
asAdmin(): /*elided*/ any;
asGuest(): /*elided*/ any;
asInactive(): /*elided*/ any;
build(): User;
};
/**
* Authenticated user builder
*/
declare const authenticatedUserBuilder: () => {
withAccessToken(token: string): /*elided*/ any;
withRefreshToken(token: string): /*elided*/ any;
withExpiresIn(seconds: number): /*elided*/ any;
withPermissions(permissions: string[]): /*elided*/ any;
withAdminPermissions(): /*elided*/ any;
build(): AuthenticatedUser;
};
/**
* Create user input builder
*/
declare const createUserInputBuilder: () => {
withEmail(email: string): /*elided*/ any;
withPassword(password: string): /*elided*/ any;
withDisplayName(displayName: string): /*elided*/ any;
withRole(role: UserRole): /*elided*/ any;
build(): CreateUserInput;
};
/**
* Create multiple users
*/
declare const createUsers: (count: number, customizer?: (builder: ReturnType<typeof userBuilder>, index: number) => void) => User[];
/**
* API response test data builders
* @module @orchard9ai/testing-utils/builders/api
*/
/**
* API response builder
*/
declare const apiResponseBuilder: <T = any>() => {
withData(data: T): /*elided*/ any;
withMeta(meta: Record<string, any>): /*elided*/ any;
withTimestamp(timestamp: string): /*elided*/ any;
build(): ApiResponse<T>;
};
/**
* API error builder
*/
declare const apiErrorBuilder: () => {
withCode(code: string): /*elided*/ any;
withMessage(message: string): /*elided*/ any;
withDetails(details: Record<string, any>): /*elided*/ any;
withFields(fields: Record<string, string[]>): /*elided*/ any;
asValidationError(): /*elided*/ any;
asNotFoundError(): /*elided*/ any;
asUnauthorizedError(): /*elided*/ any;
build(): ApiError;
};
/**
* API error response builder
*/
declare const apiErrorResponseBuilder: () => {
withError(error: ApiError): /*elided*/ any;
withRequestId(requestId: string): /*elided*/ any;
asValidationError(): /*elided*/ any;
asNotFound(): /*elided*/ any;
asUnauthorized(): /*elided*/ any;
build(): ApiErrorResponse;
};
/**
* Paginated response builder
*/
declare const paginatedResponseBuilder: <T = any>() => {
withData(data: T[]): /*elided*/ any;
withTotal(total: number): /*elided*/ any;
withPage(page: number): /*elided*/ any;
withPerPage(perPage: number): /*elided*/ any;
asFirstPage(): /*elided*/ any;
asLastPage(): /*elided*/ any;
asEmptyResult(): /*elided*/ any;
build(): PaginatedResponse<T>;
};
/**
* Batch response builder
*/
declare const batchResponseBuilder: <T = any>() => {
withSucceeded(items: Array<{
id: string;
result: T;
}>): /*elided*/ any;
withFailed(items: Array<{
id: string;
error: ApiError;
}>): /*elided*/ any;
withDuration(ms: number): /*elided*/ any;
allSucceeded(count: number, resultFactory: () => T): /*elided*/ any;
allFailed(count: number): /*elided*/ any;
build(): BatchResponse<T>;
};
/**
* Health check response builder
*/
declare const healthCheckResponseBuilder: () => {
withStatus(status: "healthy" | "degraded" | "unhealthy"): /*elided*/ any;
withVersion(version: string): /*elided*/ any;
withUptime(seconds: number): /*elided*/ any;
withCheck(check: HealthCheck): /*elided*/ any;
asHealthy(): /*elided*/ any;
asDegraded(): /*elided*/ any;
asUnhealthy(): /*elided*/ any;
build(): HealthCheckResponse;
};
/**
* Fetch mock utilities
* @module @orchard9ai/testing-utils/mocks/fetch
*/
interface MockFetchOptions {
/** Response data */
data?: any;
/** HTTP status code */
status?: number;
/** Response headers */
headers?: Record<string, string>;
/** Delay in milliseconds */
delay?: number;
/** Should reject */
reject?: boolean;
/** Error to throw */
error?: Error;
}
/**
* Mock fetch implementation
*/
declare class MockFetch {
private mocks;
private defaultMock?;
private calls;
/**
* Set default mock response
*/
setDefault(options: MockFetchOptions): void;
/**
* Mock specific URL
*/
mockUrl(url: string | RegExp, options: MockFetchOptions): void;
/**
* Mock API response
*/
mockApiResponse<T>(url: string | RegExp, data: T, options?: Partial<MockFetchOptions>): void;
/**
* Mock API error
*/
mockApiError(url: string | RegExp, error: ApiErrorResponse, options?: Partial<MockFetchOptions>): void;
/**
* Get fetch implementation
*/
getFetch(): typeof fetch;
/**
* Get all calls
*/
getCalls(): Array<{
url: string;
options: RequestInit | undefined;
}>;
/**
* Get calls for specific URL
*/
getCallsFor(url: string | RegExp): Array<{
url: string;
options: RequestInit | undefined;
}>;
/**
* Assert URL was called
*/
assertCalled(url: string | RegExp, times?: number): void;
/**
* Assert URL was not called
*/
assertNotCalled(url: string | RegExp): void;
/**
* Reset mocks
*/
reset(): void;
}
/**
* Create mock fetch instance
*/
declare function createMockFetch(): MockFetch;
/**
* Install mock fetch globally
*/
declare function installMockFetch(mockFetch: MockFetch): void;
/**
* Restore original fetch
*/
declare function restoreFetch(): void;
/**
* Async testing utilities
* @module @orchard9ai/testing-utils/utils/async
*/
/**
* Wait for a condition to be true
*/
declare function waitFor(condition: () => boolean | Promise<boolean>, options?: {
timeout?: number;
interval?: number;
}): Promise<void>;
/**
* Wait for next tick
*/
declare function waitForNextTick(): Promise<void>;
/**
* Wait for microtasks to complete
*/
declare function flushMicrotasks(): Promise<void>;
/**
* Retry an async function
*/
declare function retry<T>(fn: () => Promise<T>, options?: {
times?: number;
delay?: number;
onError?: (error: Error, attempt: number) => void;
}): Promise<T>;
/**
* Create a deferred promise
*/
declare function createDeferred<T>(): {
promise: Promise<T>;
resolve: (value: T) => void;
reject: (error: Error) => void;
};
/**
* Wait for async updates with act
*/
declare function waitForAsync(fn?: () => void | Promise<void>): Promise<void>;
/**
* Create a timeout promise
*/
declare function timeout(ms: number, message?: string): Promise<never>;
/**
* Race with timeout
*/
declare function withTimeout<T>(promise: Promise<T>, ms: number, message?: string): Promise<T>;
/**
* Delay execution
*/
declare function delay(ms: number): Promise<void>;
/**
* Create an abortable promise
*/
declare function createAbortable<T>(fn: (signal: AbortSignal) => Promise<T>): {
promise: Promise<T>;
abort: () => void;
};
/**
* Poll until condition is met
*/
declare function poll<T>(fn: () => T | Promise<T>, predicate: (value: T) => boolean, options?: {
timeout?: number;
interval?: number;
}): Promise<T>;
/**
* Create a promise that resolves after all pending timers
*/
declare function flushTimers(): Promise<void>;
/**
* Advance timers by time
*/
declare function advanceTimersByTime(ms: number): Promise<void>;
/**
* Configure axe for testing
*/
declare const axeConfig: jest_axe.JestAxe;
/**
* Check element for accessibility violations
*/
declare function checkA11y(element: Element | Document, options?: {
rules?: Record<string, {
enabled: boolean;
}>;
runOnly?: string[];
exclude?: string[];
}): Promise<axe.AxeResults>;
/**
* Assert no accessibility violations
*/
declare function expectNoA11yViolations(element: Element | Document, options?: Parameters<typeof checkA11y>[1]): Promise<void>;
/**
* Get accessibility tree
*/
declare function getAccessibilityTree(element: Element): string;
/**
* Check keyboard navigation
*/
declare function checkKeyboardNavigation(element: Element): {
focusableElements: Element[];
tabOrder: Element[];
hasSkipLinks: boolean;
};
/**
* Check ARIA labels
*/
declare function checkAriaLabels(element: Element): {
unlabeledInputs: Element[];
unlabeledButtons: Element[];
missingAltTexts: Element[];
invalidAria: Element[];
};
/**
* Assert focus is managed correctly
*/
declare function assertFocusManagement(element: Element): void;
/**
* Assert proper ARIA usage
*/
declare function assertAriaCompliance(element: Element): void;
/**
* @orchard9ai/testing-utils
*
* Testing utilities for Orchard9 platform
*/
declare const VERSION = "0.1.0";
export { MockFetch, type MockFetchOptions, type ProvidersConfig, VERSION, advanceTimersByTime, apiErrorBuilder, apiErrorResponseBuilder, apiResponseBuilder, assertAriaCompliance, assertFocusManagement, authenticatedUserBuilder, axeConfig, batchResponseBuilder, checkA11y, checkAriaLabels, checkKeyboardNavigation, createAbortable, createDeferred, createMockFetch, createUserInputBuilder, createUsers, createWrapper, delay, expectNoA11yViolations, flushMicrotasks, flushTimers, getAccessibilityTree, healthCheckResponseBuilder, installMockFetch, paginatedResponseBuilder, poll, render, renderHook, renderWithProviders, restoreFetch, retry, timeout, userBuilder, waitFor, waitForAsync, waitForNextTick, withTimeout };