Skip to content

Commit 02c70c7

Browse files
authored
Add onKeyringRequest to snaps-jest (#2777)
Add possibility to test `onKeyringRequest` with `snaps-jest`. Fixes: #2775 Keyring test example: ```typescript describe("onKeyringRequest", () => { it("sends keyring request", async () => { const { onKeyringRequest } = await installSnap(); const response = await onKeyringRequest( { origin: "https://metamask.github.io", params: { options: { privateKey: "foo bar" } }, method: "keyring_createAccount" }); expect(response).toBe({ /* Add expected result here */ }); }); }); ```
1 parent fae7855 commit 02c70c7

File tree

6 files changed

+161
-0
lines changed

6 files changed

+161
-0
lines changed

packages/snaps-jest/README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,39 @@ describe('MySnap', () => {
329329
});
330330
```
331331

332+
### `snap.onKeyringRequest`
333+
334+
The `onKeyringRequest` function can be used to process keyring request. It takes
335+
few arguments, which are similar to a JSON-RPC request object. It returns
336+
a promise that resolves to the response from the keyring request handler.
337+
338+
```js
339+
import { installSnap } from '@metamask/snaps-jest';
340+
341+
describe('onKeyringRequest', () => {
342+
it('sends keyring request', async () => {
343+
const { onKeyringRequest } = await installSnap();
344+
345+
const response = await onKeyringRequest({
346+
origin: 'https://metamask.github.io',
347+
params: {
348+
options: {
349+
privateKey: 'foo-bar',
350+
},
351+
},
352+
method: 'keyring_createAccount',
353+
});
354+
355+
expect(response).toBe({
356+
/* Add expected result here */
357+
});
358+
});
359+
});
360+
```
361+
362+
It returns an object with a response, and some additional metadata, which can be
363+
checked using the [Jest matchers](#jest-matchers):
364+
332365
### Jest matchers
333366

334367
`@metamask/snaps-jest` includes a set of Jest matchers that can be used to

packages/snaps-jest/src/helpers.test.tsx

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,46 @@ describe('installSnap', () => {
731731
});
732732
});
733733

734+
describe('onKeyringRequest', () => {
735+
it('sends a keyring request and returns the result', async () => {
736+
jest.spyOn(console, 'log').mockImplementation();
737+
738+
const { snapId, close: closeServer } = await getMockServer({
739+
sourceCode: `
740+
module.exports.onKeyringRequest = async ({ origin, request }) => {
741+
return request;
742+
}
743+
`,
744+
});
745+
746+
const { onKeyringRequest, close } = await installSnap(snapId);
747+
const response = await onKeyringRequest({
748+
origin: 'metamask.io',
749+
params: {},
750+
method: 'keyring_listAccounts',
751+
});
752+
753+
expect(response).toStrictEqual(
754+
expect.objectContaining({
755+
response: {
756+
result: {
757+
params: {},
758+
id: 1,
759+
method: 'keyring_listAccounts',
760+
jsonrpc: '2.0',
761+
},
762+
},
763+
}),
764+
);
765+
766+
// `close` is deprecated because the Jest environment will automatically
767+
// close the Snap when the test finishes. However, we still need to close
768+
// the Snap in this test because it's run outside the Jest environment.
769+
await close();
770+
await closeServer();
771+
});
772+
});
773+
734774
describe('mockJsonRpc', () => {
735775
it('mocks a JSON-RPC method', async () => {
736776
jest.spyOn(console, 'log').mockImplementation();

packages/snaps-jest/src/helpers.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ export async function installSnap<
178178
onCronjob,
179179
runCronjob,
180180
onHomePage,
181+
onKeyringRequest,
181182
mockJsonRpc,
182183
close,
183184
} = await getEnvironment().installSnap(...resolvedOptions);
@@ -190,6 +191,7 @@ export async function installSnap<
190191
onCronjob,
191192
runCronjob,
192193
onHomePage,
194+
onKeyringRequest,
193195
mockJsonRpc,
194196
close: async () => {
195197
log('Closing execution service.');

packages/snaps-simulation/src/helpers.test.tsx

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,45 @@ describe('helpers', () => {
465465
});
466466
});
467467

468+
describe('onKeyringRequest', () => {
469+
it('sends a keyring request and returns the result', async () => {
470+
jest.spyOn(console, 'log').mockImplementation();
471+
472+
const { snapId, close: closeServer } = await getMockServer({
473+
sourceCode: `
474+
module.exports.onKeyringRequest = async ({ origin, request }) => {
475+
return { success: true };
476+
}
477+
`,
478+
});
479+
480+
const { onKeyringRequest, close } = await installSnap(snapId);
481+
const response = await onKeyringRequest({
482+
origin: 'metamask.io',
483+
params: {
484+
foo: 'bar',
485+
},
486+
method: 'keyring_createAccount',
487+
});
488+
489+
expect(response).toStrictEqual(
490+
expect.objectContaining({
491+
response: {
492+
result: {
493+
success: true,
494+
},
495+
},
496+
}),
497+
);
498+
499+
// `close` is deprecated because the Jest environment will automatically
500+
// close the Snap when the test finishes. However, we still need to close
501+
// the Snap in this test because it's run outside the Jest environment.
502+
await close();
503+
await closeServer();
504+
});
505+
});
506+
468507
describe('mockJsonRpc', () => {
469508
it('mocks a JSON-RPC method', async () => {
470509
jest.spyOn(console, 'log').mockImplementation();

packages/snaps-simulation/src/helpers.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@ import {
1616
import type {
1717
CronjobOptions,
1818
JsonRpcMockOptions,
19+
KeyringOptions,
1920
RequestOptions,
2021
SignatureOptions,
2122
SnapRequest,
2223
SnapResponseWithInterface,
24+
SnapResponseWithoutInterface,
2325
TransactionOptions,
2426
} from './types';
2527

@@ -114,6 +116,16 @@ export type SnapHelpers = {
114116
*/
115117
onHomePage(): Promise<SnapResponseWithInterface>;
116118

119+
/**
120+
* Send a keyring request to the Snap.
121+
*
122+
* @param keyringRequest - Keyring request.
123+
* @returns The response.
124+
*/
125+
onKeyringRequest(
126+
keyringRequest: KeyringOptions,
127+
): Promise<SnapResponseWithoutInterface>;
128+
117129
/**
118130
* Mock a JSON-RPC request. This will cause the snap to respond with the
119131
* specified response when a request with the specified method is sent.
@@ -216,6 +228,24 @@ export function getHelpers({
216228
});
217229
};
218230

231+
const onKeyringRequest = async (
232+
request: KeyringOptions,
233+
): Promise<SnapResponseWithoutInterface> => {
234+
log('Sending keyring request %o.', request);
235+
236+
const response = await handleRequest({
237+
snapId,
238+
store,
239+
executionService,
240+
runSaga,
241+
controllerMessenger,
242+
handler: HandlerType.OnKeyringRequest,
243+
request,
244+
});
245+
246+
return response;
247+
};
248+
219249
return {
220250
request: (request) => {
221251
log('Sending request %o.', request);
@@ -234,6 +264,8 @@ export function getHelpers({
234264
onTransaction,
235265
sendTransaction: onTransaction,
236266

267+
onKeyringRequest,
268+
237269
onSignature: async (
238270
request: unknown,
239271
): Promise<SnapResponseWithInterface> => {

packages/snaps-simulation/src/types.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ export type CronjobOptions = Omit<RequestOptions, 'origin'>;
6262
*/
6363
export type TransactionOptions = Infer<typeof TransactionOptionsStruct>;
6464

65+
/**
66+
* The options to use for keyring requests.
67+
*/
68+
export type KeyringOptions = RequestOptions;
69+
6570
/**
6671
* The options to use for signature requests.
6772
*
@@ -405,6 +410,16 @@ export type Snap = {
405410
*/
406411
onHomePage(): Promise<SnapResponseWithInterface>;
407412

413+
/**
414+
* Send a keyring to the Snap.
415+
*
416+
* @param keyringRequest - Keyring request options.
417+
* @returns The response.
418+
*/
419+
onKeyringRequest(
420+
keyringRequest: KeyringOptions,
421+
): Promise<SnapResponseWithoutInterface>;
422+
408423
/**
409424
* Mock a JSON-RPC request. This will cause the snap to respond with the
410425
* specified response when a request with the specified method is sent.

0 commit comments

Comments
 (0)