UNPKG

@metamask/snaps-simulation

Version:

A simulation framework for MetaMask Snaps, enabling headless testing of Snaps in a controlled environment

505 lines 17.5 kB
import type { NotificationType, EnumToUnion, TrackableError, TraceRequest } from "@metamask/snaps-sdk"; import type { JSXElement } from "@metamask/snaps-sdk/jsx"; import type { InferMatching } from "@metamask/snaps-utils"; import type { Infer } from "@metamask/superstruct"; import type { CaipChainId, Json, JsonRpcId, JsonRpcParams } from "@metamask/utils"; import type { NameLookupOptionsStruct, SignatureOptionsStruct, SnapOptionsStruct, SnapResponseStruct, TransactionOptionsStruct } from "./structs.cjs"; export type RequestOptions = { /** * The JSON-RPC request ID. */ id?: JsonRpcId; /** * The JSON-RPC method. */ method: string; /** * The JSON-RPC params. */ params?: JsonRpcParams; /** * The origin to send the request from. */ origin?: string; }; /** * The `runCronjob` options. This is the same as {@link RequestOptions}, except * that it does not have an `origin` property. */ export type CronjobOptions = Omit<RequestOptions, 'origin'>; /** * The options to use for transaction requests. * * @property chainId - The CAIP-2 chain ID to send the transaction on. Defaults * to `eip155:1`. * @property origin - The origin to send the transaction from. Defaults to * `metamask.io`. * @property from - The address to send the transaction from. Defaults to a * randomly generated address. * @property to - The address to send the transaction to. Defaults to a randomly * generated address. * @property value - The value to send with the transaction. Defaults to `0`. * @property data - The data to send with the transaction. Defaults to `0x`. * @property gasLimit - The gas limit to use for the transaction. Defaults to * `21_000`. * @property maxFeePerGas - The maximum fee per gas to use for the transaction. * Defaults to `1`. * @property maxPriorityFeePerGas - The maximum priority fee per gas to use for * the transaction. Defaults to `1`. * @property nonce - The nonce to use for the transaction. Defaults to `0`. */ export type TransactionOptions = Infer<typeof TransactionOptionsStruct>; /** * The options to use for keyring requests. */ export type KeyringOptions = RequestOptions; /** * The options to use for name lookup requests. * * @property chainId - Chain ID. * @property domain - Domain name to lookup and resolve. * @property address - Address to lookup and resolve. */ export type NameLookupOptions = Infer<typeof NameLookupOptionsStruct>; /** * The options to use for signature requests. * * @property origin - The origin to send the signature request from. Defaults to * `metamask.io`. * @property from - The address to send the signature from. Defaults to a * randomly generated address. * @property data - The data to sign. Defaults to `0x`. * @property signatureMethod - The signature method. */ export type SignatureOptions = Infer<typeof SignatureOptionsStruct>; /** * The options to use for requests to the snap. * * @property timeout - The timeout in milliseconds to use. Defaults to `1000`. */ export type SnapOptions = Infer<typeof SnapOptionsStruct>; /** * Options for uploading a file. * * @property fileName - The name of the file. By default, this is inferred from * the file path if it's a path, and defaults to an empty string if it's a * `Uint8Array`. * @property contentType - The content type of the file. By default, this is * inferred from the file name if it's a path, and defaults to * `application/octet-stream` if it's a `Uint8Array` or the content type cannot * be inferred from the file name. */ export type FileOptions = { fileName?: string; contentType?: string; }; export type SnapInterfaceActions = { /** * Click on an interface element. * * @param name - The element name to click. */ clickElement(name: string): Promise<void>; /** * Type a value in a interface field. * * @param name - The element name to type in. * @param value - The value to type. */ typeInField(name: string, value: string): Promise<void>; /** * Select an option with a value in a dropdown. * * @param name - The element name to type in. * @param value - The value to type. */ selectInDropdown(name: string, value: string): Promise<void>; /** * Choose an option with a value from radio group. * * @param name - The element name to type in. * @param value - The value to type. */ selectFromRadioGroup(name: string, value: string): Promise<void>; /** * Choose an option with a value from a Selector, AccountSelector or AssetSelector component. * * @param name - The element name to type in. * @param value - The value to select. */ selectFromSelector(name: string, value: string): Promise<void>; /** * Upload a file. * * @param name - The element name to upload the file to. * @param file - The file to upload. This can be a path to a file or a * `Uint8Array` containing the file contents. If this is a path, the file is * resolved relative to the current working directory. * @param options - The file options. * @param options.fileName - The name of the file. By default, this is * inferred from the file path if it's a path, and defaults to an empty string * if it's a `Uint8Array`. * @param options.contentType - The content type of the file. By default, this * is inferred from the file name if it's a path, and defaults to * `application/octet-stream` if it's a `Uint8Array` or the content type * cannot be inferred from the file name. */ uploadFile(name: string, file: string | Uint8Array, options?: FileOptions): Promise<void>; /** * Wait for the interface to be updated. */ waitForUpdate: () => Promise<SnapHandlerInterface>; }; /** * A `snap_dialog` alert interface. */ export type SnapAlertInterface = { /** * The type of the interface. This is always `alert`. */ type: 'alert'; /** * The content to show in the alert. */ content: JSXElement; /** * The ID of the interface. */ id: string; /** * Close the alert. */ ok(): Promise<void>; }; /** * A `snap_dialog` confirmation interface. */ export type SnapConfirmationInterface = { /** * The type of the interface. This is always `confirmation`. */ type: 'confirmation'; /** * The content to show in the confirmation. */ content: JSXElement; /** * The ID of the interface. */ id: string; /** * Close the confirmation. */ ok(): Promise<void>; /** * Cancel the confirmation. */ cancel(): Promise<void>; }; /** * A `snap_dialog` prompt interface. */ export type SnapPromptInterface = { /** * The type of the interface. This is always `prompt`. */ type: 'prompt'; /** * The content to show in the prompt. */ content: JSXElement; /** * The ID of the interface. */ id: string; /** * Close the prompt. * * @param value - The value to close the prompt with. */ ok(value?: string): Promise<void>; /** * Cancel the prompt. */ cancel(): Promise<void>; }; /** * A `snap_dialog` default interface that has a Footer with two buttons defined. * The approval of this confirmation is handled by the snap. */ export type DefaultSnapInterfaceWithFooter = { /** * The content to show in the interface. */ content: JSXElement; /** * The ID of the interface. */ id: string; }; /** * A `snap_dialog` default interface that has a Footer with one button defined. * A cancel button is automatically applied to the interface in this case. */ export type DefaultSnapInterfaceWithPartialFooter = DefaultSnapInterfaceWithFooter & { /** * Cancel the dialog. */ cancel(): Promise<void>; }; /** * A `snap_dialog` default interface that has no Footer defined. * A cancel and ok button is automatically applied to the interface in this case. */ export type DefaultSnapInterfaceWithoutFooter = DefaultSnapInterfaceWithPartialFooter & { /** * Close the dialog. * */ ok(): Promise<void>; }; export type DefaultSnapInterface = (DefaultSnapInterfaceWithFooter | DefaultSnapInterfaceWithPartialFooter | DefaultSnapInterfaceWithoutFooter) & { type?: never; }; export type SnapInterface = (SnapAlertInterface | SnapConfirmationInterface | SnapPromptInterface | DefaultSnapInterface) & SnapInterfaceActions; export type SnapRequestObject = { /** * Get a user interface object from a snap. This will throw an error if the * snap does not show a user interface within the timeout. * * @param options - The options to use. * @param options.timeout - The timeout in milliseconds to use. Defaults to * `1000`. * @returns The user interface object. */ getInterface(options?: SnapOptions): Promise<SnapInterface>; }; /** * A pending request object. This is a promise with extra * {@link SnapRequestObject} fields. */ export type SnapRequest = Promise<SnapResponse> & SnapRequestObject; /** * The options to use for mocking a JSON-RPC request. */ export type JsonRpcMockOptions = { /** * The JSON-RPC request method. */ method: string; /** * The JSON-RPC response, which will be returned when a request with the * specified method is sent. */ result: Json; }; /** * This is the main entry point to interact with the snap. It is returned by * {@link installSnap}, and has methods to send requests to the snap. * * @example * import { installSnap } from '@metamask/snaps-jest'; * * const snap = await installSnap(); * const response = await snap.request({ method: 'hello' }); * * expect(response).toRespondWith('Hello, world!'); */ export type Snap = { /** * Send a JSON-RPC request to the snap. * * @param request - The request. This is similar to a JSON-RPC request, but * has an extra `origin` field. * @returns The response promise, with extra {@link SnapRequestObject} fields. */ request(request: RequestOptions): SnapRequest; /** * Send a transaction to the snap. * * @param transaction - The transaction. This is similar to an Ethereum * transaction object, but has an extra `origin` field. Any missing fields * will be filled in with default values. * @returns The response. */ onTransaction(transaction?: Partial<TransactionOptions>): Promise<SnapResponseWithInterface>; /** * Send a transaction to the snap. * * @param transaction - The transaction. This is similar to an Ethereum * transaction object, but has an extra `origin` field. Any missing fields * will be filled in with default values. * @returns The response. * @deprecated Use {@link onTransaction} instead. */ sendTransaction(transaction?: Partial<TransactionOptions>): Promise<SnapResponseWithInterface>; /** * Send a signature request to the snap. * * @param signature - The signature request object. Contains the params from * the various signature methods, but has an extra `origin` and `signatureMethod` field. * Any missing fields will be filled in with default values. * @returns The response. */ onSignature(signature?: Partial<SignatureOptions>): Promise<SnapResponseWithInterface>; /** * Run a cronjob in the snap. This is similar to {@link request}, but the * request will be sent to the `onCronjob` method of the snap. * * @param cronjob - The cronjob request. This is similar to a JSON-RPC * request, and is normally specified in the snap manifest, under the * `endowment:cronjob` permission. * @returns The response promise, with extra {@link SnapRequestObject} fields. */ onCronjob(cronjob?: Partial<CronjobOptions>): SnapRequest; /** * Run a cronjob in the snap. This is similar to {@link request}, but the * request will be sent to the `onCronjob` method of the snap. * * @param cronjob - The cronjob request. This is similar to a JSON-RPC * request, and is normally specified in the snap manifest, under the * `endowment:cronjob` permission. * @returns The response promise, with extra {@link SnapRequestObject} fields. * @deprecated Use {@link onCronjob} instead. */ runCronjob(cronjob: CronjobOptions): SnapRequest; /** * Run a background event in the snap. This is similar to {@link request}, but the * request will be sent to the `onCronjob` method of the snap. * * @param backgroundEvent - The cronjob request. This is similar to a JSON-RPC * request, and is normally specified as the `request` param in the `snap_scheduleBackgroundEvent` method. * @returns The response promise, with extra {@link SnapRequestObject} fields. */ onBackgroundEvent(backgroundEvent: CronjobOptions): SnapRequest; /** * Get the response from the snap's `onHomePage` method. * * @returns The response. */ onHomePage(): Promise<SnapResponseWithInterface>; /** * Get the response from the snap's `onSettingsPage` method. * * @returns The response. */ onSettingsPage(): Promise<SnapResponseWithInterface>; /** * Send a keyring to the Snap. * * @param keyringRequest - Keyring request options. * @returns The response. */ onKeyringRequest(keyringRequest: KeyringOptions): SnapRequest; /** * Get the response from the Snap's `onInstall` handler. * * @returns The response. */ onInstall(request?: Pick<RequestOptions, 'origin'>): SnapRequest; /** * Get the response from the Snap's `onUpdate` handler. * * @returns The response. */ onUpdate(request?: Pick<RequestOptions, 'origin'>): SnapRequest; /** * Get the response from the Snap's `onStart` handler. * * @returns The response. */ onStart(request?: Pick<RequestOptions, 'origin'>): SnapRequest; /** * Get the response from the Snap's `onNameLookup` handler. * * @returns The response. */ onNameLookup(nameLookupRequest: NameLookupOptions): Promise<SnapResponseWithoutInterface>; /** * Send a JSON-RPC protocol request to the Snap. * * @param scope - A CAIP-2 scope. * @param request - The request. This is similar to a JSON-RPC request, but * has an extra `origin` field. * @returns The response promise, with extra {@link SnapRequestObject} fields. */ onProtocolRequest(scope: CaipChainId, request: RequestOptions): Promise<SnapResponseWithoutInterface>; /** * Send a JSON-RPC client request to the Snap. * * @param request - The JSON-RPC request. * @returns The response promise, with extra {@link SnapRequestObject} fields. */ onClientRequest(request: Omit<RequestOptions, 'origin'>): SnapRequest; /** * Mock a JSON-RPC request. This will cause the snap to respond with the * specified response when a request with the specified method is sent. * * @param mock - The mock options. * @param mock.method - The JSON-RPC request method. * @param mock.result - The JSON-RPC response, which will be returned when a * request with the specified method is sent. * @example * import { installSnap } from '@metamask/snaps-jest'; * * // In the test * const snap = await installSnap(); * snap.mockJsonRpc({ method: 'eth_accounts', result: ['0x1234'] }); * * // In the Snap * const response = * await ethereum.request({ method: 'eth_accounts' }); // ['0x1234'] */ mockJsonRpc(mock: JsonRpcMockOptions): { /** * Remove the mock. */ unmock(): void; }; /** * Close the page running the snap. This is mainly useful for cleaning up * the test environment, and calling it is not strictly necessary. * * @returns A promise that resolves when the page is closed. * @deprecated Snaps are now automatically closed when the test ends. This * method will be removed in a future release. */ close(): Promise<void>; }; export type SnapHandlerInterface = { content: JSXElement; } & SnapInterfaceActions; export type TrackedSnapResponseData = { errors: TrackableError[]; events: { event: string; properties?: Record<string, Json>; sensitiveProperties?: Record<string, Json>; }[]; traces: TraceRequest[]; }; export type SnapResponseWithInterface = { id: string; response: { result: Json; } | { error: Json; }; notifications: { id: string; message: string; type: EnumToUnion<NotificationType>; title?: string | undefined; content?: string | undefined; footerLink?: { text: string; href: string; } | undefined; }[]; tracked: TrackedSnapResponseData; getInterface(): SnapHandlerInterface; }; export type SnapResponseWithoutInterface = Omit<SnapResponseWithInterface, 'getInterface'>; export type SnapResponseType = SnapResponseWithoutInterface | SnapResponseWithInterface; export type SnapResponse = InferMatching<typeof SnapResponseStruct, SnapResponseType>; //# sourceMappingURL=types.d.cts.map