UNPKG

@fedify/testing

Version:

Testing utilities for Fedify applications

274 lines (272 loc) 12 kB
import { TracerProvider } from "@opentelemetry/api"; import { ActorCallbackSetters, ActorDispatcher, ActorKeyPair, CollectionCallbackSetters, CollectionDispatcher, Context, Federation, FederationFetchOptions, FederationStartQueueOptions, InboxListenerSetters, Message, NodeInfoDispatcher, ObjectCallbackSetters, ObjectDispatcher, ParseUriResult, RequestContext, RouteActivityOptions, SendActivityOptions, SendActivityOptionsForCollection, SenderKeyPair } from "@fedify/fedify/federation"; import { Activity, Actor, Collection, Hashtag, LookupObjectOptions, Object as Object$1, Recipient, TraverseCollectionOptions } from "@fedify/fedify/vocab"; import { ResourceDescriptor } from "@fedify/fedify/webfinger"; import { JsonValue, NodeInfo } from "@fedify/fedify/nodeinfo"; import { DocumentLoader } from "@fedify/fedify/runtime"; //#region mock.d.ts /** * Represents a sent activity with metadata about how it was sent. * @since 1.8.0 */ interface SentActivity { /** Whether the activity was queued or sent immediately. */ queued: boolean; /** Which queue was used (if queued). */ queue?: "inbox" | "outbox" | "fanout"; /** The activity that was sent. */ activity: Activity; /** The order in which the activity was sent (auto-incrementing counter). */ sentOrder: number; } /** * A mock implementation of the {@link Federation} interface for unit testing. * This class provides a way to test Fedify applications without needing * a real federation setup. * * @example * ```typescript * import { Create } from "@fedify/fedify/vocab"; * import { MockFederation } from "@fedify/testing"; * * // Create a mock federation with contextData * const federation = new MockFederation<{ userId: string }>({ * contextData: { userId: "test-user" } * }); * * // Set up inbox listeners * federation * .setInboxListeners("/users/{identifier}/inbox") * .on(Create, async (ctx, activity) => { * console.log("Received:", activity); * }); * * // Simulate receiving an activity * const createActivity = new Create({ * id: new URL("https://example.com/create/1"), * actor: new URL("https://example.com/users/alice") * }); * await federation.receiveActivity(createActivity); * ``` * * @typeParam TContextData The context data to pass to the {@link Context}. * @since 1.8.0 */ declare class MockFederation<TContextData> implements Federation<TContextData> { private options; sentActivities: SentActivity[]; queueStarted: boolean; private activeQueues; sentCounter: number; private nodeInfoDispatcher?; private actorDispatchers; actorPath?: string; inboxPath?: string; outboxPath?: string; followingPath?: string; followersPath?: string; likedPath?: string; featuredPath?: string; featuredTagsPath?: string; nodeInfoPath?: string; sharedInboxPath?: string; objectPaths: Map<string, string>; private objectDispatchers; private inboxDispatcher?; private outboxDispatcher?; private followingDispatcher?; private followersDispatcher?; private likedDispatcher?; private featuredDispatcher?; private featuredTagsDispatcher?; private inboxListeners; private contextData?; private receivedActivities; constructor(options?: { contextData?: TContextData; origin?: string; tracerProvider?: TracerProvider; }); setNodeInfoDispatcher(path: string, dispatcher: NodeInfoDispatcher<TContextData>): void; setActorDispatcher(path: `${string}{identifier}${string}` | `${string}{handle}${string}`, dispatcher: ActorDispatcher<TContextData>): ActorCallbackSetters<TContextData>; setObjectDispatcher<TObject extends Object$1, TParam extends string>(cls: (new (...args: any[]) => TObject) & { typeId: URL; }, path: string, dispatcher: ObjectDispatcher<TContextData, TObject, TParam>): ObjectCallbackSetters<TContextData, TObject, TParam>; setInboxDispatcher(_path: `${string}{identifier}${string}` | `${string}{handle}${string}`, dispatcher: CollectionDispatcher<Activity, RequestContext<TContextData>, TContextData, void>): CollectionCallbackSetters<RequestContext<TContextData>, TContextData, void>; setOutboxDispatcher(path: `${string}{identifier}${string}` | `${string}{handle}${string}`, dispatcher: CollectionDispatcher<Activity, RequestContext<TContextData>, TContextData, void>): CollectionCallbackSetters<RequestContext<TContextData>, TContextData, void>; setFollowingDispatcher(path: `${string}{identifier}${string}` | `${string}{handle}${string}`, dispatcher: CollectionDispatcher<Actor | URL, RequestContext<TContextData>, TContextData, void>): CollectionCallbackSetters<RequestContext<TContextData>, TContextData, void>; setFollowersDispatcher(path: `${string}{identifier}${string}` | `${string}{handle}${string}`, dispatcher: CollectionDispatcher<Recipient, Context<TContextData>, TContextData, URL>): CollectionCallbackSetters<Context<TContextData>, TContextData, URL>; setLikedDispatcher(path: `${string}{identifier}${string}` | `${string}{handle}${string}`, dispatcher: CollectionDispatcher<Object$1 | URL, RequestContext<TContextData>, TContextData, void>): CollectionCallbackSetters<RequestContext<TContextData>, TContextData, void>; setFeaturedDispatcher(path: `${string}{identifier}${string}` | `${string}{handle}${string}`, dispatcher: CollectionDispatcher<Object$1, RequestContext<TContextData>, TContextData, void>): CollectionCallbackSetters<RequestContext<TContextData>, TContextData, void>; setFeaturedTagsDispatcher(path: `${string}{identifier}${string}` | `${string}{handle}${string}`, dispatcher: CollectionDispatcher<Hashtag, RequestContext<TContextData>, TContextData, void>): CollectionCallbackSetters<RequestContext<TContextData>, TContextData, void>; setInboxListeners(inboxPath: `${string}{identifier}${string}` | `${string}{handle}${string}`, sharedInboxPath?: string): InboxListenerSetters<TContextData>; startQueue(contextData: TContextData, options?: FederationStartQueueOptions): Promise<void>; processQueuedTask(contextData: TContextData, _message: Message): Promise<void>; createContext(baseUrl: URL, contextData: TContextData): Context<TContextData>; createContext(request: Request, contextData: TContextData): RequestContext<TContextData>; fetch(request: Request, options: FederationFetchOptions<TContextData>): Promise<Response>; /** * Simulates receiving an activity. This method is specific to the mock * implementation and is used for testing purposes. * * @param activity The activity to receive. * @returns A promise that resolves when the activity has been processed. * @since 1.8.0 */ receiveActivity(activity: Activity): Promise<void>; /** * Clears all sent activities from the mock federation. * This method is specific to the mock implementation and is used for * testing purposes. * * @since 1.8.0 */ reset(): void; } /** * A mock implementation of the {@link Context} interface for unit testing. * This class provides a way to test Fedify applications without needing * a real federation context. * * @example * ```typescript * import { Person, Create } from "@fedify/fedify/vocab"; * import { MockContext, MockFederation } from "@fedify/testing"; * * // Create a mock context * const mockFederation = new MockFederation<{ userId: string }>(); * const context = new MockContext({ * url: new URL("https://example.com"), * data: { userId: "test-user" }, * federation: mockFederation * }); * * // Send an activity * const recipient = new Person({ id: new URL("https://example.com/users/bob") }); * const activity = new Create({ * id: new URL("https://example.com/create/1"), * actor: new URL("https://example.com/users/alice") * }); * await context.sendActivity( * { identifier: "alice" }, * recipient, * activity * ); * * // Check sent activities * const sent = context.getSentActivities(); * console.log(sent[0].activity); * ``` * * @typeParam TContextData The context data to pass to the {@link Context}. * @since 1.8.0 */ declare class MockContext<TContextData> implements Context<TContextData> { readonly origin: string; readonly canonicalOrigin: string; readonly host: string; readonly hostname: string; readonly data: TContextData; readonly federation: Federation<TContextData>; readonly documentLoader: DocumentLoader; readonly contextLoader: DocumentLoader; readonly tracerProvider: TracerProvider; private sentActivities; constructor(options: { url?: URL; data: TContextData; federation: Federation<TContextData>; documentLoader?: DocumentLoader; contextLoader?: DocumentLoader; tracerProvider?: TracerProvider; }); clone(data: TContextData): Context<TContextData>; getNodeInfoUri(): URL; getActorUri(identifier: string): URL; getObjectUri<TObject extends Object$1>(cls: (new (...args: any[]) => TObject) & { typeId: URL; }, values: Record<string, string>): URL; getOutboxUri(identifier: string): URL; getInboxUri(identifier: string): URL; getInboxUri(): URL; getFollowingUri(identifier: string): URL; getFollowersUri(identifier: string): URL; getLikedUri(identifier: string): URL; getFeaturedUri(identifier: string): URL; getFeaturedTagsUri(identifier: string): URL; parseUri(uri: URL): ParseUriResult | null; getActorKeyPairs(_identifier: string): Promise<ActorKeyPair[]>; getDocumentLoader(params: { handle: string; } | { identifier: string; }): Promise<DocumentLoader>; getDocumentLoader(params: { keyId: URL; privateKey: CryptoKey; }): DocumentLoader; lookupObject(_uri: URL | string, _options?: LookupObjectOptions): Promise<Object$1 | null>; traverseCollection<TItem, TContext extends Context<TContextData>>(_collection: Collection | URL | null, _options?: TraverseCollectionOptions): AsyncIterable<TItem>; lookupNodeInfo(url: URL | string, options?: { parse?: "strict" | "best-effort"; } & any): Promise<NodeInfo | undefined>; lookupNodeInfo(url: URL | string, options?: { parse: "none"; } & any): Promise<JsonValue | undefined>; lookupWebFinger(_resource: URL | `acct:${string}@${string}` | string, _options?: any): Promise<ResourceDescriptor | null>; sendActivity(sender: SenderKeyPair | SenderKeyPair[] | { identifier: string; } | { username: string; } | { handle: string; }, recipients: Recipient | Recipient[], activity: Activity, options?: SendActivityOptions): Promise<void>; sendActivity(sender: { identifier: string; } | { username: string; } | { handle: string; }, recipients: "followers", activity: Activity, options?: SendActivityOptionsForCollection): Promise<void>; sendActivity(sender: SenderKeyPair | SenderKeyPair[] | { identifier: string; } | { username: string; } | { handle: string; }, recipients: Recipient | Recipient[], activity: Activity, options?: SendActivityOptions): Promise<void>; sendActivity(sender: { identifier: string; } | { username: string; } | { handle: string; }, recipients: "followers", activity: Activity, options?: SendActivityOptionsForCollection): Promise<void>; routeActivity(_recipient: string | null, _activity: Activity, _options?: RouteActivityOptions): Promise<boolean>; /** * Gets all activities that have been sent through this mock context. * This method is specific to the mock implementation and is used for * testing purposes. * * @returns An array of sent activity records. */ getSentActivities(): Array<{ sender: SenderKeyPair | SenderKeyPair[] | { identifier: string; } | { username: string; } | { handle: string; }; recipients: Recipient | Recipient[] | "followers"; activity: Activity; }>; /** * Clears all sent activities from the mock context. * This method is specific to the mock implementation and is used for * testing purposes. */ reset(): void; } //#endregion export { MockContext, MockFederation, SentActivity };