@metamask/snaps-simulation
Version:
A simulation framework for MetaMask Snaps, enabling headless testing of Snaps in a controlled environment
1 lines • 22.5 kB
Source Map (JSON)
{"version":3,"file":"helpers.cjs","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"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","sourcesContent":["import { HandlerType } from '@metamask/snaps-utils';\nimport { create } from '@metamask/superstruct';\nimport type { CaipChainId } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\n\nimport { rootLogger } from './logger';\nimport type { SimulationOptions } from './options';\nimport { handleRequest } from './request';\nimport type { InstalledSnap } from './simulation';\nimport { addJsonRpcMock, removeJsonRpcMock } from './store';\nimport {\n assertIsResponseWithInterface,\n JsonRpcMockOptionsStruct,\n NameLookupOptionsStruct,\n SignatureOptionsStruct,\n TransactionOptionsStruct,\n} from './structs';\nimport type {\n CronjobOptions,\n JsonRpcMockOptions,\n KeyringOptions,\n NameLookupOptions,\n RequestOptions,\n SignatureOptions,\n SnapRequest,\n SnapResponseWithInterface,\n SnapResponseWithoutInterface,\n TransactionOptions,\n} from './types';\n\nconst log = createModuleLogger(rootLogger, 'helpers');\n\n/**\n * This is the main entry point to interact with the snap. It is returned by\n * {@link installSnap}, and has methods to send requests to the snap.\n *\n * @example\n * import { installSnap } from '@metamask/snaps-jest';\n *\n * const snap = await installSnap();\n * const response = await snap.request({ method: 'hello' });\n *\n * expect(response).toRespondWith('Hello, world!');\n */\nexport type SnapHelpers = {\n /**\n * Send a JSON-RPC request to the snap.\n *\n * @param request - The request. This is similar to a JSON-RPC request, but\n * has an extra `origin` field.\n * @returns The response promise, with extra {@link SnapRequestObject} fields.\n */\n request(request: RequestOptions): SnapRequest;\n\n /**\n * Send a transaction to the snap.\n *\n * @param transaction - The transaction. This is similar to an Ethereum\n * transaction object, but has an extra `origin` field. Any missing fields\n * will be filled in with default values.\n * @returns The response.\n */\n onTransaction(\n transaction?: Partial<TransactionOptions>,\n ): Promise<SnapResponseWithInterface>;\n\n /**\n * Send a transaction to the snap.\n *\n * @param transaction - The transaction. This is similar to an Ethereum\n * transaction object, but has an extra `origin` field. Any missing fields\n * will be filled in with default values.\n * @returns The response.\n * @deprecated Use {@link onTransaction} instead.\n */\n sendTransaction(\n transaction?: Partial<TransactionOptions>,\n ): Promise<SnapResponseWithInterface>;\n\n /**\n * Send a signature request to the snap.\n *\n * @param signature - The signature request object. Contains the params from\n * the various signature methods, but has an extra `origin` and `signatureMethod` field.\n * Any missing fields will be filled in with default values.\n * @returns The response.\n */\n onSignature(\n signature?: Partial<SignatureOptions>,\n ): Promise<SnapResponseWithInterface>;\n\n /**\n * Run a cronjob in the snap. This is similar to {@link request}, but the\n * request will be sent to the `onCronjob` method of the snap.\n *\n * @param cronjob - The cronjob request. This is similar to a JSON-RPC\n * request, and is normally specified in the snap manifest, under the\n * `endowment:cronjob` permission.\n * @returns The response promise, with extra {@link SnapRequestObject} fields.\n */\n onCronjob(cronjob?: Partial<CronjobOptions>): SnapRequest;\n\n /**\n * Run a cronjob in the snap. This is similar to {@link request}, but the\n * request will be sent to the `onCronjob` method of the snap.\n *\n * @param cronjob - The cronjob request. This is similar to a JSON-RPC\n * request, and is normally specified in the snap manifest, under the\n * `endowment:cronjob` permission.\n * @returns The response promise, with extra {@link SnapRequestObject} fields.\n * @deprecated Use {@link onCronjob} instead.\n */\n runCronjob(cronjob: CronjobOptions): SnapRequest;\n\n /**\n * Run a background event in the snap. This is similar to {@link request}, but the\n * request will be sent to the `onCronjob` method of the snap.\n *\n * @param backgroundEvent - The background event request. This is similar to a JSON-RPC\n * request, and is normally specified in the `request` param of the `snap_scheduleBackgroundEvent` method.\n * @returns The response promise, with extra {@link SnapRequestObject} fields.\n */\n onBackgroundEvent(backgroundEvent: CronjobOptions): SnapRequest;\n\n /**\n * Get the response from the snap's `onHomePage` method.\n *\n * @returns The response.\n */\n onHomePage(): Promise<SnapResponseWithInterface>;\n\n /**\n * Get the response from the snap's `onSettingsPage` method.\n *\n * @returns The response.\n */\n onSettingsPage(): Promise<SnapResponseWithInterface>;\n\n /**\n * Send a keyring request to the Snap.\n *\n * @param keyringRequest - Keyring request.\n * @returns The response.\n */\n onKeyringRequest(keyringRequest: KeyringOptions): SnapRequest;\n\n /**\n * Get the response from the Snap's `onInstall` handler.\n *\n * @returns The response.\n */\n onInstall(request?: Pick<RequestOptions, 'origin'>): SnapRequest;\n\n /**\n * Get the response from the Snap's `onUpdate` handler.\n *\n * @returns The response.\n */\n onUpdate(request?: Pick<RequestOptions, 'origin'>): SnapRequest;\n\n /**\n * Get the response from the Snap's `onStart` handler.\n *\n * @returns The response.\n */\n onStart(request?: Pick<RequestOptions, 'origin'>): SnapRequest;\n\n /**\n * Get the response from the Snap's `onNameLookup` handler.\n *\n * @returns The response.\n */\n onNameLookup(\n request: NameLookupOptions,\n ): Promise<SnapResponseWithoutInterface>;\n\n /**\n * Send a JSON-RPC protocol request to the Snap.\n *\n * @param scope - A CAIP-2 scope.\n * @param request - The request. This is similar to a JSON-RPC request, but\n * has an extra `origin` field.\n * @returns The response promise, with extra {@link SnapRequestObject} fields.\n */\n onProtocolRequest(\n scope: CaipChainId,\n request: RequestOptions,\n ): Promise<SnapResponseWithoutInterface>;\n\n /**\n * Send a JSON-RPC client request to the Snap.\n *\n * @param request - The JSON-RPC request.\n * @returns The response promise, with extra {@link SnapRequestObject} fields.\n */\n onClientRequest(request: Omit<RequestOptions, 'origin'>): SnapRequest;\n\n /**\n * Mock a JSON-RPC request. This will cause the snap to respond with the\n * specified response when a request with the specified method is sent.\n *\n * @param mock - The mock options.\n * @param mock.method - The JSON-RPC request method.\n * @param mock.result - The JSON-RPC response, which will be returned when a\n * request with the specified method is sent.\n * @example\n * import { installSnap } from '@metamask/snaps-jest';\n *\n * // In the test\n * const snap = await installSnap();\n * snap.mockJsonRpc({ method: 'eth_accounts', result: ['0x1234'] });\n *\n * // In the Snap\n * const response =\n * await ethereum.request({ method: 'eth_accounts' }); // ['0x1234']\n */\n mockJsonRpc(mock: JsonRpcMockOptions): {\n /**\n * Remove the mock.\n */\n unmock(): void;\n };\n\n /**\n * Close the page running the snap. This is mainly useful for cleaning up\n * the test environment, and calling it is not strictly necessary.\n *\n * @returns A promise that resolves when the page is closed.\n */\n close(): Promise<void>;\n};\n\n/**\n * Get the helper functions for the Snap.\n *\n * @param snap - The installed Snap.\n * @param snap.snapId - The ID of the Snap.\n * @param snap.store - The Redux store.\n * @param snap.executionService - The execution service.\n * @param snap.runSaga - The `runSaga` function.\n * @param snap.controllerMessenger - The controller messenger.\n * @param snap.options - The simulation options.\n * @returns The Snap helpers.\n */\nexport function getHelpers({\n snapId,\n store,\n executionService,\n runSaga,\n controllerMessenger,\n options,\n}: InstalledSnap & { options: SimulationOptions }): SnapHelpers {\n const onTransaction = async (\n request: TransactionOptions,\n ): Promise<SnapResponseWithInterface> => {\n log('Sending transaction %o.', request);\n\n const {\n origin: transactionOrigin,\n chainId,\n ...transaction\n } = create(request, TransactionOptionsStruct);\n\n const response = await handleRequest({\n snapId,\n store,\n executionService,\n runSaga,\n controllerMessenger,\n simulationOptions: options,\n handler: HandlerType.OnTransaction,\n request: {\n method: '',\n params: {\n chainId,\n transaction,\n transactionOrigin,\n },\n },\n });\n\n assertIsResponseWithInterface(response);\n\n return response;\n };\n\n // This can't be async because it returns a `SnapRequest`.\n // eslint-disable-next-line @typescript-eslint/promise-function-async\n const onCronjob = (request: CronjobOptions) => {\n log('Running cronjob %o.', options);\n\n return handleRequest({\n snapId,\n store,\n executionService,\n controllerMessenger,\n simulationOptions: options,\n runSaga,\n handler: HandlerType.OnCronjob,\n request,\n });\n };\n\n // This can't be async because it returns a `SnapRequest`.\n // eslint-disable-next-line @typescript-eslint/promise-function-async\n const onKeyringRequest = (request: KeyringOptions) => {\n log('Sending keyring request %o.', request);\n\n return handleRequest({\n snapId,\n store,\n executionService,\n runSaga,\n controllerMessenger,\n simulationOptions: options,\n handler: HandlerType.OnKeyringRequest,\n request,\n });\n };\n\n return {\n // This can't be async because it returns a `SnapRequest`.\n // eslint-disable-next-line @typescript-eslint/promise-function-async\n request: (request) => {\n log('Sending request %o.', request);\n\n return handleRequest({\n snapId,\n store,\n executionService,\n controllerMessenger,\n simulationOptions: options,\n runSaga,\n handler: HandlerType.OnRpcRequest,\n request,\n });\n },\n\n onTransaction,\n sendTransaction: onTransaction,\n\n onKeyringRequest,\n\n // This can't be async because it returns a `SnapRequest`.\n // eslint-disable-next-line @typescript-eslint/promise-function-async\n onInstall: (request?: Pick<RequestOptions, 'origin'>) => {\n log('Running onInstall handler.');\n\n return handleRequest({\n snapId,\n store,\n executionService,\n controllerMessenger,\n simulationOptions: options,\n runSaga,\n handler: HandlerType.OnInstall,\n request: {\n method: '',\n ...request,\n },\n });\n },\n\n // This can't be async because it returns a `SnapRequest`.\n // eslint-disable-next-line @typescript-eslint/promise-function-async\n onUpdate: (request?: Pick<RequestOptions, 'origin'>) => {\n log('Running onUpdate handler.');\n\n return handleRequest({\n snapId,\n store,\n executionService,\n controllerMessenger,\n simulationOptions: options,\n runSaga,\n handler: HandlerType.OnUpdate,\n request: {\n method: '',\n ...request,\n },\n });\n },\n\n // This can't be async because it returns a `SnapRequest`.\n // eslint-disable-next-line @typescript-eslint/promise-function-async\n onStart: (request?: Pick<RequestOptions, 'origin'>) => {\n log('Running onStart handler.');\n\n return handleRequest({\n snapId,\n store,\n executionService,\n controllerMessenger,\n simulationOptions: options,\n runSaga,\n handler: HandlerType.OnStart,\n request: {\n method: '',\n ...request,\n },\n });\n },\n\n onNameLookup: async (\n nameLookupOptions: NameLookupOptions,\n ): Promise<SnapResponseWithoutInterface> => {\n log('Requesting name lookup %o.', nameLookupOptions);\n\n const params = create(nameLookupOptions, NameLookupOptionsStruct);\n\n const response = await handleRequest({\n snapId,\n store,\n executionService,\n controllerMessenger,\n simulationOptions: options,\n runSaga,\n handler: HandlerType.OnNameLookup,\n request: {\n method: '',\n params,\n },\n });\n\n return response;\n },\n\n onSignature: async (\n request: unknown,\n ): Promise<SnapResponseWithInterface> => {\n log('Requesting signature %o.', request);\n\n const { origin: signatureOrigin, ...signature } = create(\n request,\n SignatureOptionsStruct,\n );\n\n const response = await handleRequest({\n snapId,\n store,\n executionService,\n controllerMessenger,\n simulationOptions: options,\n runSaga,\n handler: HandlerType.OnSignature,\n request: {\n method: '',\n params: {\n signature,\n signatureOrigin,\n },\n },\n });\n\n assertIsResponseWithInterface(response);\n\n return response;\n },\n\n onCronjob,\n runCronjob: onCronjob,\n onBackgroundEvent: onCronjob,\n\n onHomePage: async (): Promise<SnapResponseWithInterface> => {\n log('Rendering home page.');\n\n const response = await handleRequest({\n snapId,\n store,\n executionService,\n controllerMessenger,\n simulationOptions: options,\n runSaga,\n handler: HandlerType.OnHomePage,\n request: {\n method: '',\n },\n });\n\n assertIsResponseWithInterface(response);\n\n return response;\n },\n\n onSettingsPage: async (): Promise<SnapResponseWithInterface> => {\n log('Rendering settings page.');\n\n const response = await handleRequest({\n snapId,\n store,\n executionService,\n controllerMessenger,\n simulationOptions: options,\n runSaga,\n handler: HandlerType.OnSettingsPage,\n request: {\n method: '',\n },\n });\n\n assertIsResponseWithInterface(response);\n\n return response;\n },\n\n onProtocolRequest: async (\n scope,\n rawRequest,\n ): Promise<SnapResponseWithoutInterface> => {\n log('Sending protocol request.');\n\n const request = {\n jsonrpc: '2.0' as const,\n id: rawRequest.id ?? 1,\n method: rawRequest.method,\n ...(rawRequest.params ? { params: rawRequest.params } : {}),\n };\n\n const response = await handleRequest({\n snapId,\n store,\n executionService,\n controllerMessenger,\n simulationOptions: options,\n runSaga,\n handler: HandlerType.OnProtocolRequest,\n request: {\n origin: rawRequest.origin,\n method: '',\n params: {\n scope,\n request,\n },\n },\n });\n\n return response;\n },\n\n // This can't be async because it returns a `SnapRequest`.\n // eslint-disable-next-line @typescript-eslint/promise-function-async\n onClientRequest: (request) => {\n log('Sending client request.');\n\n return handleRequest({\n snapId,\n store,\n executionService,\n controllerMessenger,\n simulationOptions: options,\n runSaga,\n handler: HandlerType.OnClientRequest,\n request,\n });\n },\n\n mockJsonRpc(mock: JsonRpcMockOptions) {\n log('Mocking JSON-RPC request %o.', mock);\n\n const { method, result } = create(mock, JsonRpcMockOptionsStruct);\n store.dispatch(addJsonRpcMock({ method, result }));\n\n return {\n unmock() {\n log('Unmocking JSON-RPC request %o.', mock);\n\n store.dispatch(removeJsonRpcMock(method));\n },\n };\n },\n\n close: async () => {\n log('Closing execution service.');\n await executionService.terminateAllSnaps();\n },\n };\n}\n"]}