Skip to content

Commit

Permalink
Move helper functions to simulation package (#2769)
Browse files Browse the repository at this point in the history
To make the simulation package easier to work with, I've moved all the
helper functions (`request`, `onTransaction`, etc.) to the simulation
package.

There are no functional changes in this PR, it just moves code around.
  • Loading branch information
Mrtenz authored Sep 27, 2024
1 parent a1e9563 commit b8cca6c
Show file tree
Hide file tree
Showing 15 changed files with 1,105 additions and 650 deletions.
5 changes: 3 additions & 2 deletions packages/snaps-jest/src/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import type {
} from '@jest/environment';
import type { AbstractExecutionService } from '@metamask/snaps-controllers';
import type { SnapId } from '@metamask/snaps-sdk';
import { installSnap } from '@metamask/snaps-simulation';
import type {
InstalledSnap,
InstallSnapOptions,
SnapHelpers,
} from '@metamask/snaps-simulation';
import { installSnap } from '@metamask/snaps-simulation';
import { assert, createModuleLogger } from '@metamask/utils';
import type { Server } from 'http';
import NodeEnvironment from 'jest-environment-node';
Expand All @@ -31,7 +32,7 @@ export class SnapsEnvironment extends NodeEnvironment {

#server: Server | undefined;

#instance: InstalledSnap | undefined;
#instance: (InstalledSnap & SnapHelpers) | undefined;

/**
* Constructor.
Expand Down
188 changes: 19 additions & 169 deletions packages/snaps-jest/src/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,10 @@
import type { AbstractExecutionService } from '@metamask/snaps-controllers';
import type { SnapId } from '@metamask/snaps-sdk';
import type { InstallSnapOptions } from '@metamask/snaps-simulation';
import {
JsonRpcMockOptionsStruct,
SignatureOptionsStruct,
handleRequest,
TransactionOptionsStruct,
addJsonRpcMock,
removeJsonRpcMock,
SnapResponseWithInterfaceStruct,
} from '@metamask/snaps-simulation';
import { HandlerType, logInfo } from '@metamask/snaps-utils';
import { create } from '@metamask/superstruct';
import { assertStruct, createModuleLogger } from '@metamask/utils';
import type { InstallSnapOptions, Snap } from '@metamask/snaps-simulation';
import { logInfo } from '@metamask/snaps-utils';
import { createModuleLogger } from '@metamask/utils';

import { rootLogger, getEnvironment } from './internals';
import type {
SnapResponseWithInterface,
CronjobOptions,
JsonRpcMockOptions,
Snap,
SnapResponse,
TransactionOptions,
} from './types';

const log = createModuleLogger(rootLogger, 'helpers');

Expand All @@ -48,17 +30,6 @@ function getOptions<
return [snapId, options];
}

/**
* Ensure that the actual response contains `getInterface`.
*
* @param response - The response of the handler.
*/
function assertIsResponseWithInterface(
response: SnapResponse,
): asserts response is SnapResponseWithInterface {
assertStruct(response, SnapResponseWithInterfaceStruct);
}

/**
* Load a snap into the environment. This is the main entry point for testing
* snaps: It returns a {@link Snap} object that can be used to interact with the
Expand Down Expand Up @@ -200,154 +171,33 @@ export async function installSnap<
): Promise<Snap> {
const resolvedOptions = getOptions(snapId, options);
const {
snapId: installedSnapId,
store,
executionService,
runSaga,
controllerMessenger,
request,
onTransaction,
sendTransaction,
onSignature,
onCronjob,
runCronjob,
onHomePage,
mockJsonRpc,
close,
} = await getEnvironment().installSnap(...resolvedOptions);

const onTransaction = async (
request: TransactionOptions,
): Promise<SnapResponseWithInterface> => {
log('Sending transaction %o.', request);

const {
origin: transactionOrigin,
chainId,
...transaction
} = create(request, TransactionOptionsStruct);

const response = await handleRequest({
snapId: installedSnapId,
store,
executionService,
runSaga,
controllerMessenger,
handler: HandlerType.OnTransaction,
request: {
method: '',
params: {
chainId,
transaction,
transactionOrigin,
},
},
});

assertIsResponseWithInterface(response);

return response;
};

const onCronjob = (request: CronjobOptions) => {
log('Running cronjob %o.', options);

return handleRequest({
snapId: installedSnapId,
store,
executionService,
controllerMessenger,
runSaga,
handler: HandlerType.OnCronjob,
request,
});
};

return {
request: (request) => {
log('Sending request %o.', request);

return handleRequest({
snapId: installedSnapId,
store,
executionService,
controllerMessenger,
runSaga,
handler: HandlerType.OnRpcRequest,
request,
});
},

request,
onTransaction,
sendTransaction: onTransaction,

onSignature: async (
request: unknown,
): Promise<SnapResponseWithInterface> => {
log('Requesting signature %o.', request);

const { origin: signatureOrigin, ...signature } = create(
request,
SignatureOptionsStruct,
);

const response = await handleRequest({
snapId: installedSnapId,
store,
executionService,
controllerMessenger,
runSaga,
handler: HandlerType.OnSignature,
request: {
method: '',
params: {
signature,
signatureOrigin,
},
},
});

assertIsResponseWithInterface(response);

return response;
},

sendTransaction,
onSignature,
onCronjob,
runCronjob: onCronjob,

onHomePage: async (): Promise<SnapResponseWithInterface> => {
log('Rendering home page.');

const response = await handleRequest({
snapId: installedSnapId,
store,
executionService,
controllerMessenger,
runSaga,
handler: HandlerType.OnHomePage,
request: {
method: '',
},
});

assertIsResponseWithInterface(response);

return response;
},

mockJsonRpc(mock: JsonRpcMockOptions) {
log('Mocking JSON-RPC request %o.', mock);

const { method, result } = create(mock, JsonRpcMockOptionsStruct);
store.dispatch(addJsonRpcMock({ method, result }));

return {
unmock() {
log('Unmocking JSON-RPC request %o.', mock);

store.dispatch(removeJsonRpcMock(method));
},
};
},

runCronjob,
onHomePage,
mockJsonRpc,
close: async () => {
log('Closing execution service.');
logInfo(
'Calling `snap.close()` is deprecated, and will be removed in a future release. Snaps are now automatically closed when the test ends.',
);

await executionService.terminateAllSnaps();
await close();
},
};
}
27 changes: 26 additions & 1 deletion packages/snaps-jest/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import './global';
export { default, default as TestEnvironment } from './environment';
export * from './helpers';
export * from './options';
export * from './types';

export {
assertCustomDialogHasNoFooter,
Expand All @@ -14,3 +13,29 @@ export {
assertIsCustomDialog,
assertIsPromptDialog,
} from '@metamask/snaps-simulation';

export type {
CronjobOptions,
DefaultSnapInterface,
DefaultSnapInterfaceWithFooter,
DefaultSnapInterfaceWithPartialFooter,
DefaultSnapInterfaceWithoutFooter,
FileOptions,
RequestOptions,
SignatureOptions,
Snap,
SnapAlertInterface,
SnapConfirmationInterface,
SnapHandlerInterface,
SnapInterface,
SnapInterfaceActions,
SnapOptions,
SnapPromptInterface,
SnapResponse,
SnapResponseType,
SnapResponseWithInterface,
SnapResponseWithoutInterface,
SnapRequest,
SnapRequestObject,
TransactionOptions,
} from '@metamask/snaps-simulation';
3 changes: 1 addition & 2 deletions packages/snaps-jest/src/matchers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type {
} from '@metamask/snaps-sdk';
import type { JSXElement } from '@metamask/snaps-sdk/jsx';
import { isJSXElementUnsafe } from '@metamask/snaps-sdk/jsx';
import type { SnapResponse } from '@metamask/snaps-simulation';
import {
InterfaceStruct,
SnapResponseStruct,
Expand All @@ -35,8 +36,6 @@ import {
RECEIVED_COLOR,
} from 'jest-matcher-utils';

import type { SnapResponse } from './types';

/**
* Ensure that the actual value is a response from the `request` function.
*
Expand Down
7 changes: 5 additions & 2 deletions packages/snaps-jest/src/test-utils/response.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { JSXElement } from '@metamask/snaps-sdk/jsx';

import type { SnapHandlerInterface, SnapResponse } from '../types';
import type {
SnapHandlerInterface,
SnapResponse,
} from '@metamask/snaps-simulation';

/**
* Get a mock response.
Expand Down Expand Up @@ -40,6 +42,7 @@ export function getMockInterfaceResponse(
typeInField: jest.fn(),
selectInDropdown: jest.fn(),
selectFromRadioGroup: jest.fn(),
selectFromSelector: jest.fn(),
uploadFile: jest.fn(),
};
}
1 change: 0 additions & 1 deletion packages/snaps-jest/src/types/index.ts

This file was deleted.

Loading

0 comments on commit b8cca6c

Please sign in to comment.