@metamask/snaps-jest 6.0.2 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/CHANGELOG.md +12 -1
  2. package/README.md +100 -7
  3. package/dist/{chunk-6RXFM4YC.js → chunk-2JAGD4N6.js} +3 -3
  4. package/dist/{chunk-7YD4IW43.mjs → chunk-3M4GRUMH.mjs} +3 -6
  5. package/dist/chunk-3M4GRUMH.mjs.map +1 -0
  6. package/dist/{chunk-7BFTEFLS.mjs → chunk-5U5WB3SM.mjs} +5 -3
  7. package/dist/chunk-5U5WB3SM.mjs.map +1 -0
  8. package/dist/chunk-6POKT4OO.js +127 -0
  9. package/dist/chunk-6POKT4OO.js.map +1 -0
  10. package/dist/{chunk-7VILST6M.mjs → chunk-BVGI3E45.mjs} +2 -2
  11. package/dist/chunk-CKRORVDW.js +1 -0
  12. package/dist/{chunk-6HW5NGCB.js → chunk-DTDYOBCI.js} +3 -3
  13. package/dist/{chunk-WIFOID2P.mjs → chunk-EDEJD326.mjs} +20 -10
  14. package/dist/chunk-EDEJD326.mjs.map +1 -0
  15. package/dist/{chunk-B4QZXXQY.js → chunk-FIZAYEHV.js} +4 -4
  16. package/dist/chunk-I5P52IMF.mjs +223 -0
  17. package/dist/chunk-I5P52IMF.mjs.map +1 -0
  18. package/dist/{chunk-T2BE4O5H.js → chunk-IDGD7TZ7.js} +33 -23
  19. package/dist/chunk-IDGD7TZ7.js.map +1 -0
  20. package/dist/{chunk-BS24WMRW.mjs → chunk-LG3VKXGH.mjs} +2 -2
  21. package/dist/{chunk-C2ONPIIB.js → chunk-MCYTJUDG.js} +10 -15
  22. package/dist/chunk-MCYTJUDG.js.map +1 -0
  23. package/dist/chunk-PVMIH6OB.mjs +127 -0
  24. package/dist/chunk-PVMIH6OB.mjs.map +1 -0
  25. package/dist/chunk-S2HLITUN.js +1 -0
  26. package/dist/{chunk-ISWZ7XZ5.js → chunk-SB5EPHE3.js} +5 -3
  27. package/dist/chunk-SB5EPHE3.js.map +1 -0
  28. package/dist/{chunk-HBLJOACO.mjs → chunk-TAIJXTLU.mjs} +2 -10
  29. package/dist/chunk-TAIJXTLU.mjs.map +1 -0
  30. package/dist/chunk-TGZ7WOTJ.mjs +1 -0
  31. package/dist/chunk-UDOXICJK.mjs +1 -0
  32. package/dist/{chunk-3HU56QS3.mjs → chunk-VSUNWJMQ.mjs} +8 -13
  33. package/dist/chunk-VSUNWJMQ.mjs.map +1 -0
  34. package/dist/{chunk-TO46ICOZ.js → chunk-WMLSD6B5.js} +3 -6
  35. package/dist/chunk-WMLSD6B5.js.map +1 -0
  36. package/dist/{chunk-3SNZ4SPY.mjs → chunk-X5IPMTHO.mjs} +2 -2
  37. package/dist/chunk-Y4DKEF7Y.js +223 -0
  38. package/dist/chunk-Y4DKEF7Y.js.map +1 -0
  39. package/dist/{chunk-7J34R6YW.mjs → chunk-YEVKBYKO.mjs} +35 -25
  40. package/dist/chunk-YEVKBYKO.mjs.map +1 -0
  41. package/dist/{chunk-5PLDD7ZC.js → chunk-Z35PCKFD.js} +24 -14
  42. package/dist/chunk-Z35PCKFD.js.map +1 -0
  43. package/dist/{chunk-LXSNRZV4.js → chunk-ZWN4SO2V.js} +5 -13
  44. package/dist/chunk-ZWN4SO2V.js.map +1 -0
  45. package/dist/environment.js +13 -14
  46. package/dist/environment.mjs +12 -13
  47. package/dist/global.js +2 -0
  48. package/dist/global.js.map +1 -0
  49. package/dist/global.mjs +2 -0
  50. package/dist/global.mjs.map +1 -0
  51. package/dist/helpers.js +13 -14
  52. package/dist/helpers.mjs +12 -13
  53. package/dist/index.js +16 -16
  54. package/dist/index.mjs +15 -15
  55. package/dist/internals/index.js +27 -14
  56. package/dist/internals/index.mjs +30 -17
  57. package/dist/internals/request.js +12 -11
  58. package/dist/internals/request.mjs +13 -12
  59. package/dist/internals/simulation/controllers.js +6 -7
  60. package/dist/internals/simulation/controllers.mjs +5 -6
  61. package/dist/internals/simulation/index.js +17 -10
  62. package/dist/internals/simulation/index.mjs +17 -10
  63. package/dist/internals/simulation/interface.js +11 -3
  64. package/dist/internals/simulation/interface.mjs +12 -4
  65. package/dist/internals/simulation/methods/hooks/index.js +4 -10
  66. package/dist/internals/simulation/methods/hooks/index.mjs +3 -9
  67. package/dist/internals/simulation/methods/hooks/notifications.js +1 -1
  68. package/dist/internals/simulation/methods/hooks/notifications.mjs +1 -1
  69. package/dist/internals/simulation/methods/hooks/show-dialog.js +1 -1
  70. package/dist/internals/simulation/methods/hooks/show-dialog.mjs +1 -1
  71. package/dist/internals/simulation/methods/hooks/state.js +3 -3
  72. package/dist/internals/simulation/methods/hooks/state.mjs +2 -2
  73. package/dist/internals/simulation/methods/index.js +5 -6
  74. package/dist/internals/simulation/methods/index.mjs +4 -5
  75. package/dist/internals/simulation/methods/specifications.js +5 -6
  76. package/dist/internals/simulation/methods/specifications.mjs +4 -5
  77. package/dist/internals/simulation/simulation.js +8 -9
  78. package/dist/internals/simulation/simulation.mjs +7 -8
  79. package/dist/internals/simulation/store/index.js +2 -2
  80. package/dist/internals/simulation/store/index.mjs +1 -1
  81. package/dist/internals/simulation/store/store.js +2 -2
  82. package/dist/internals/simulation/store/store.mjs +1 -1
  83. package/dist/internals/structs.js +6 -2
  84. package/dist/internals/structs.mjs +5 -1
  85. package/dist/matchers.js +13 -14
  86. package/dist/matchers.mjs +12 -13
  87. package/dist/setup.js +12 -13
  88. package/dist/setup.mjs +12 -13
  89. package/dist/tsconfig.build.tsbuildinfo +1 -1
  90. package/dist/types/global.d.ts +69 -0
  91. package/dist/types/index.d.ts +1 -0
  92. package/dist/types/internals/request.d.ts +13 -4
  93. package/dist/types/internals/simulation/interface.d.ts +47 -4
  94. package/dist/types/internals/simulation/methods/hooks/index.d.ts +0 -1
  95. package/dist/types/internals/simulation/methods/hooks/state.d.ts +2 -1
  96. package/dist/types/internals/simulation/store/store.d.ts +1 -2
  97. package/dist/types/internals/structs.d.ts +79 -156
  98. package/dist/types/types.d.ts +42 -21
  99. package/package.json +6 -6
  100. package/dist/chunk-2X23DUDP.mjs +0 -22
  101. package/dist/chunk-2X23DUDP.mjs.map +0 -1
  102. package/dist/chunk-3HU56QS3.mjs.map +0 -1
  103. package/dist/chunk-5PLDD7ZC.js.map +0 -1
  104. package/dist/chunk-6MVV44M5.mjs +0 -76
  105. package/dist/chunk-6MVV44M5.mjs.map +0 -1
  106. package/dist/chunk-7BFTEFLS.mjs.map +0 -1
  107. package/dist/chunk-7J34R6YW.mjs.map +0 -1
  108. package/dist/chunk-7YD4IW43.mjs.map +0 -1
  109. package/dist/chunk-C2ONPIIB.js.map +0 -1
  110. package/dist/chunk-HBLJOACO.mjs.map +0 -1
  111. package/dist/chunk-HNH5UAKZ.js +0 -80
  112. package/dist/chunk-HNH5UAKZ.js.map +0 -1
  113. package/dist/chunk-ISWZ7XZ5.js.map +0 -1
  114. package/dist/chunk-LXSNRZV4.js.map +0 -1
  115. package/dist/chunk-LYK6EGZU.mjs +0 -80
  116. package/dist/chunk-LYK6EGZU.mjs.map +0 -1
  117. package/dist/chunk-RD7GQCPL.js +0 -22
  118. package/dist/chunk-RD7GQCPL.js.map +0 -1
  119. package/dist/chunk-T2BE4O5H.js.map +0 -1
  120. package/dist/chunk-TO46ICOZ.js.map +0 -1
  121. package/dist/chunk-U5BLLHIU.js +0 -1
  122. package/dist/chunk-V6LFAN3U.mjs +0 -1
  123. package/dist/chunk-WIFOID2P.mjs.map +0 -1
  124. package/dist/chunk-ZAQZRYPW.js +0 -76
  125. package/dist/chunk-ZAQZRYPW.js.map +0 -1
  126. package/dist/internals/simulation/methods/hooks/encryption.js +0 -10
  127. package/dist/internals/simulation/methods/hooks/encryption.mjs +0 -10
  128. package/dist/types/internals/simulation/methods/hooks/encryption.d.ts +0 -29
  129. /package/dist/{chunk-6RXFM4YC.js.map → chunk-2JAGD4N6.js.map} +0 -0
  130. /package/dist/{chunk-7VILST6M.mjs.map → chunk-BVGI3E45.mjs.map} +0 -0
  131. /package/dist/{chunk-U5BLLHIU.js.map → chunk-CKRORVDW.js.map} +0 -0
  132. /package/dist/{chunk-6HW5NGCB.js.map → chunk-DTDYOBCI.js.map} +0 -0
  133. /package/dist/{chunk-B4QZXXQY.js.map → chunk-FIZAYEHV.js.map} +0 -0
  134. /package/dist/{chunk-BS24WMRW.mjs.map → chunk-LG3VKXGH.mjs.map} +0 -0
  135. /package/dist/{internals/simulation/methods/hooks/encryption.js.map → chunk-S2HLITUN.js.map} +0 -0
  136. /package/dist/{chunk-V6LFAN3U.mjs.map → chunk-TGZ7WOTJ.mjs.map} +0 -0
  137. /package/dist/{internals/simulation/methods/hooks/encryption.mjs.map → chunk-UDOXICJK.mjs.map} +0 -0
  138. /package/dist/{chunk-3SNZ4SPY.mjs.map → chunk-X5IPMTHO.mjs.map} +0 -0
package/CHANGELOG.md CHANGED
@@ -6,6 +6,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [7.0.0]
10
+ ### Added
11
+ - **BREAKING:** Support Interactive UI in `snaps-jest` ([#2286](https://github.com/MetaMask/snaps/pull/2286))
12
+ - Remove `content` from the Snap response, instead `getInterface()` must be used
13
+ - `clickElement` and `typeInField` can be used on the interface return value to simulate actions
14
+
15
+ ### Changed
16
+ - Improve Jest expect types ([#2308](https://github.com/MetaMask/snaps/pull/2308))
17
+ - Refactor to support changes to encryption ([#2316](https://github.com/MetaMask/snaps/pull/2316))
18
+
9
19
  ## [6.0.2]
10
20
  ### Changed
11
21
  - Bump MetaMask dependencies ([#2270](https://github.com/MetaMask/snaps/pull/2270))
@@ -112,7 +122,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
112
122
  - The version of the package no longer needs to match the version of all other
113
123
  MetaMask Snaps packages.
114
124
 
115
- [Unreleased]: https://github.com/MetaMask/snaps/compare/@metamask/snaps-jest@6.0.2...HEAD
125
+ [Unreleased]: https://github.com/MetaMask/snaps/compare/@metamask/snaps-jest@7.0.0...HEAD
126
+ [7.0.0]: https://github.com/MetaMask/snaps/compare/@metamask/snaps-jest@6.0.2...@metamask/snaps-jest@7.0.0
116
127
  [6.0.2]: https://github.com/MetaMask/snaps/compare/@metamask/snaps-jest@6.0.1...@metamask/snaps-jest@6.0.2
117
128
  [6.0.1]: https://github.com/MetaMask/snaps/compare/@metamask/snaps-jest@6.0.0...@metamask/snaps-jest@6.0.1
118
129
  [6.0.0]: https://github.com/MetaMask/snaps/compare/@metamask/snaps-jest@5.0.0...@metamask/snaps-jest@6.0.0
package/README.md CHANGED
@@ -194,7 +194,7 @@ All properties are optional, and have sensible defaults. The addresses are
194
194
  randomly generated by default. Most values can be specified as a hex string, or
195
195
  a decimal number.
196
196
 
197
- It returns an object with the user interface that was shown by the snap, in the
197
+ It returns a `getInterface` function that gets the user interface that was shown by the snap, in the
198
198
  [onTransaction](https://docs.metamask.io/snaps/reference/exports/#ontransaction)
199
199
  function.
200
200
 
@@ -214,7 +214,9 @@ describe('MySnap', () => {
214
214
  nonce: '0x0',
215
215
  });
216
216
 
217
- expect(response).toRender(panel([text('Hello, world!')]));
217
+ const screen = response.getInterface();
218
+
219
+ expect(screen).toRender(panel([text('Hello, world!')]));
218
220
  });
219
221
  });
220
222
  ```
@@ -233,7 +235,7 @@ All properties are optional, and have sensible defaults. The addresses are
233
235
  randomly generated by default. Most values can be specified as a hex string, or
234
236
  a decimal number.
235
237
 
236
- It returns an object with the user interface that was shown by the snap, in the
238
+ It returns a `getInterface` function that gets the user interface that was shown by the snap, in the
237
239
  [onSignature](https://docs.metamask.io/snaps/reference/exports/#onsignature)
238
240
  function.
239
241
 
@@ -246,7 +248,9 @@ describe('MySnap', () => {
246
248
  const { onSignature } = await installSnap(/* optional snap ID */);
247
249
  const response = await onSignature();
248
250
 
249
- expect(response).toRender(
251
+ const screen = response.getInterface();
252
+
253
+ expect(screen).toRender(
250
254
  panel([text('You are using the personal_sign method')]),
251
255
  );
252
256
  });
@@ -303,7 +307,7 @@ describe('MySnap', () => {
303
307
  ### `snap.onHomePage`
304
308
 
305
309
  The `onHomePage` function can be used to request the home page of the snap. It
306
- takes no arguments, and returns a promise that resolves to the response from the
310
+ takes no arguments, and returns a promise that contains a `getInterface` function to get the response from the
307
311
  [onHomePage](https://docs.metamask.io/snaps/reference/entry-points/#onhomepage)
308
312
  function.
309
313
 
@@ -318,7 +322,9 @@ describe('MySnap', () => {
318
322
  params: [],
319
323
  });
320
324
 
321
- expect(response).toRender(/* ... */);
325
+ const screen = response.getInterface();
326
+
327
+ expect(screen).toRender(/* ... */);
322
328
  });
323
329
  });
324
330
  ```
@@ -344,6 +350,8 @@ assert that a response from a snap matches an expected value:
344
350
 
345
351
  ### Interacting with user interfaces
346
352
 
353
+ #### `snap_dialog`
354
+
347
355
  If your snap uses `snap_dialog` to show user interfaces, you can use the
348
356
  `request.getInterface` function to interact with them. This method is present on
349
357
  the return value of the `snap.request` function.
@@ -351,7 +359,7 @@ the return value of the `snap.request` function.
351
359
  It waits for the user interface to be shown, and returns an object with
352
360
  functions that can be used to interact with the user interface.
353
361
 
354
- #### Example
362
+ ##### Example
355
363
 
356
364
  ```js
357
365
  import { installSnap } from '@metamask/snaps-jest';
@@ -384,6 +392,91 @@ describe('MySnap', () => {
384
392
  });
385
393
  ```
386
394
 
395
+ #### handlers
396
+
397
+ If your snap uses handlers that shows user interfaces (`onTransaction`, `onSignature`, `onHomePage`), you can use the
398
+ `response.getInterface` function to interact with them. This method is present on
399
+ the return value of the `snap.request` function.
400
+
401
+ It returns an object with functions that can be used to interact with the user interface.
402
+
403
+ ##### Example
404
+
405
+ ```js
406
+ import { installSnap } from '@metamask/snaps-jest';
407
+
408
+ describe('MySnap', () => {
409
+ it('should do something', async () => {
410
+ const { onHomePage } = await installSnap(/* optional snap ID */);
411
+ const response = await onHomePage({
412
+ method: 'foo',
413
+ params: [],
414
+ });
415
+
416
+ const screen = response.getInterface();
417
+
418
+ expect(screen).toRender(/* ... */);
419
+ });
420
+ });
421
+ ```
422
+
423
+ ### User interactions in user interfaces
424
+
425
+ The object returned by the `getInterface` function exposes other functions to trigger user interactions in the user interface.
426
+
427
+ - `clickElement(elementName)`: Click on a button inside the user interface. If the button with the given name does not exist in the interface this method will throw.
428
+ - `typeInField(elementName, valueToType)`: Enter a value in a field inside the user interface. If the input field with the given name des not exist in the interface this method will throw.
429
+
430
+ #### Example
431
+
432
+ ```js
433
+ import { installSnap } from '@metamask/snaps-jest';
434
+
435
+ describe('MySnap', () => {
436
+ it('should do something', async () => {
437
+ const { onHomePage } = await installSnap(/* optional snap ID */);
438
+ const response = await onHomePage({
439
+ method: 'foo',
440
+ params: [],
441
+ });
442
+
443
+ const screen = response.getInterface();
444
+
445
+ expect(screen).toRender(/* ... */);
446
+
447
+ await screen.clickElement('myButton');
448
+
449
+ const screen = response.getInterface();
450
+
451
+ expect(screen).toRender(/* ... */);
452
+ });
453
+ });
454
+ ```
455
+
456
+ ```js
457
+ import { installSnap } from '@metamask/snaps-jest';
458
+
459
+ describe('MySnap', () => {
460
+ it('should do something', async () => {
461
+ const { onHomePage } = await installSnap(/* optional snap ID */);
462
+ const response = await onHomePage({
463
+ method: 'foo',
464
+ params: [],
465
+ });
466
+
467
+ const screen = response.getInterface();
468
+
469
+ expect(screen).toRender(/* ... */);
470
+
471
+ await screen.typeInField('myField', 'the value to type');
472
+
473
+ const screen = response.getInterface();
474
+
475
+ expect(screen).toRender(/* ... */);
476
+ });
477
+ });
478
+ ```
479
+
387
480
  ## Options
388
481
 
389
482
  You can pass options to the test environment by adding a
@@ -3,7 +3,7 @@
3
3
  var _chunkT2PHS5FYjs = require('./chunk-T2PHS5FY.js');
4
4
 
5
5
 
6
- var _chunkC2ONPIIBjs = require('./chunk-C2ONPIIB.js');
6
+ var _chunkMCYTJUDGjs = require('./chunk-MCYTJUDG.js');
7
7
 
8
8
 
9
9
  var _chunkN6MAO223js = require('./chunk-N6MAO223.js');
@@ -72,7 +72,7 @@ var SnapsEnvironment = class extends _jestenvironmentnode2.default {
72
72
  */
73
73
  async installSnap(snapId = this.snapId, options = {}) {
74
74
  await _chunkPHUTP7NBjs.__privateGet.call(void 0, this, _instance)?.executionService.terminateAllSnaps();
75
- _chunkPHUTP7NBjs.__privateSet.call(void 0, this, _instance, await _chunkC2ONPIIBjs.handleInstallSnap.call(void 0, snapId, options));
75
+ _chunkPHUTP7NBjs.__privateSet.call(void 0, this, _instance, await _chunkMCYTJUDGjs.handleInstallSnap.call(void 0, snapId, options));
76
76
  return _chunkPHUTP7NBjs.__privateGet.call(void 0, this, _instance);
77
77
  }
78
78
  /**
@@ -101,4 +101,4 @@ var environment_default = SnapsEnvironment;
101
101
 
102
102
 
103
103
  exports.SnapsEnvironment = SnapsEnvironment; exports.environment_default = environment_default;
104
- //# sourceMappingURL=chunk-6RXFM4YC.js.map
104
+ //# sourceMappingURL=chunk-2JAGD4N6.js.map
@@ -15,7 +15,7 @@ import {
15
15
  // src/internals/simulation/store/store.ts
16
16
  import { configureStore } from "@reduxjs/toolkit";
17
17
  import createSagaMiddleware from "redux-saga";
18
- function createStore(password, { state, unencryptedState }) {
18
+ function createStore({ state, unencryptedState }) {
19
19
  const sagaMiddleware = createSagaMiddleware();
20
20
  const store = configureStore({
21
21
  reducer: {
@@ -29,10 +29,7 @@ function createStore(password, { state, unencryptedState }) {
29
29
  if (state) {
30
30
  store.dispatch(
31
31
  setState({
32
- state: JSON.stringify({
33
- password,
34
- value: state
35
- }),
32
+ state: JSON.stringify(state),
36
33
  encrypted: true
37
34
  })
38
35
  );
@@ -54,4 +51,4 @@ function createStore(password, { state, unencryptedState }) {
54
51
  export {
55
52
  createStore
56
53
  };
57
- //# sourceMappingURL=chunk-7YD4IW43.mjs.map
54
+ //# sourceMappingURL=chunk-3M4GRUMH.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/internals/simulation/store/store.ts"],"sourcesContent":["import { configureStore } from '@reduxjs/toolkit';\nimport createSagaMiddleware from 'redux-saga';\n\nimport type { SimulationOptions } from '../options';\nimport { mocksSlice } from './mocks';\nimport { notificationsSlice } from './notifications';\nimport { setState, stateSlice } from './state';\nimport { uiSlice } from './ui';\n\n/**\n * Create a Redux store.\n *\n * @param options - The simulation options.\n * @param options.state - The initial state for the Snap.\n * @param options.unencryptedState - The initial unencrypted state for the Snap.\n * @returns A Redux store with the default state.\n */\nexport function createStore({ state, unencryptedState }: SimulationOptions) {\n const sagaMiddleware = createSagaMiddleware();\n const store = configureStore({\n reducer: {\n mocks: mocksSlice.reducer,\n notifications: notificationsSlice.reducer,\n state: stateSlice.reducer,\n ui: uiSlice.reducer,\n },\n middleware: (getDefaultMiddleware) =>\n getDefaultMiddleware({ thunk: false }).concat(sagaMiddleware),\n });\n\n // Set initial state for the Snap.\n if (state) {\n store.dispatch(\n setState({\n state: JSON.stringify(state),\n encrypted: true,\n }),\n );\n }\n\n if (unencryptedState) {\n store.dispatch(\n setState({\n state: JSON.stringify(unencryptedState),\n encrypted: false,\n }),\n );\n }\n\n return {\n store,\n runSaga: sagaMiddleware.run.bind(sagaMiddleware),\n };\n}\n\nexport type Store = ReturnType<typeof createStore>['store'];\nexport type ApplicationState = ReturnType<Store['getState']>;\nexport type RunSagaFunction = ReturnType<typeof createStore>['runSaga'];\n"],"mappings":";;;;;;;;;;;;;;;AAAA,SAAS,sBAAsB;AAC/B,OAAO,0BAA0B;AAgB1B,SAAS,YAAY,EAAE,OAAO,iBAAiB,GAAsB;AAC1E,QAAM,iBAAiB,qBAAqB;AAC5C,QAAM,QAAQ,eAAe;AAAA,IAC3B,SAAS;AAAA,MACP,OAAO,WAAW;AAAA,MAClB,eAAe,mBAAmB;AAAA,MAClC,OAAO,WAAW;AAAA,MAClB,IAAI,QAAQ;AAAA,IACd;AAAA,IACA,YAAY,CAAC,yBACX,qBAAqB,EAAE,OAAO,MAAM,CAAC,EAAE,OAAO,cAAc;AAAA,EAChE,CAAC;AAGD,MAAI,OAAO;AACT,UAAM;AAAA,MACJ,SAAS;AAAA,QACP,OAAO,KAAK,UAAU,KAAK;AAAA,QAC3B,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAAA,EACF;AAEA,MAAI,kBAAkB;AACpB,UAAM;AAAA,MACJ,SAAS;AAAA,QACP,OAAO,KAAK,UAAU,gBAAgB;AAAA,QACtC,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA,SAAS,eAAe,IAAI,KAAK,cAAc;AAAA,EACjD;AACF;","names":[]}
@@ -5,9 +5,11 @@ import {
5
5
  } from "./chunk-MPZOXW6I.mjs";
6
6
 
7
7
  // src/internals/simulation/methods/hooks/state.ts
8
+ import { parseJson } from "@metamask/snaps-utils";
8
9
  import { put, select } from "redux-saga/effects";
9
10
  function* getSnapStateImplementation(_snapId, encrypted = true) {
10
- return yield select(getState(encrypted));
11
+ const state = yield select(getState(encrypted));
12
+ return parseJson(state);
11
13
  }
12
14
  function getGetSnapStateMethodImplementation(runSaga) {
13
15
  return (...args) => {
@@ -15,7 +17,7 @@ function getGetSnapStateMethodImplementation(runSaga) {
15
17
  };
16
18
  }
17
19
  function* updateSnapStateImplementation(_snapId, newState, encrypted = true) {
18
- yield put(setState({ state: newState, encrypted }));
20
+ yield put(setState({ state: JSON.stringify(newState), encrypted }));
19
21
  }
20
22
  function getUpdateSnapStateMethodImplementation(runSaga) {
21
23
  return (...args) => {
@@ -36,4 +38,4 @@ export {
36
38
  getUpdateSnapStateMethodImplementation,
37
39
  getClearSnapStateMethodImplementation
38
40
  };
39
- //# sourceMappingURL=chunk-7BFTEFLS.mjs.map
41
+ //# sourceMappingURL=chunk-5U5WB3SM.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/internals/simulation/methods/hooks/state.ts"],"sourcesContent":["import { parseJson } from '@metamask/snaps-utils';\nimport type { Json } from '@metamask/utils';\nimport type { SagaIterator } from 'redux-saga';\nimport { put, select } from 'redux-saga/effects';\n\nimport type { RunSagaFunction } from '../../store';\nimport { clearState, getState, setState } from '../../store';\n\n/**\n * Get the Snap state from the store.\n *\n * @param _snapId - The ID of the Snap to get the state for. This is ignored\n * because the simulator only supports one Snap.\n * @param encrypted - Whether to get the encrypted or unencrypted state.\n * Defaults to encrypted state.\n * @returns The state of the Snap.\n * @yields Selects the state from the store.\n */\nfunction* getSnapStateImplementation(\n _snapId: string,\n encrypted = true,\n): SagaIterator<string> {\n const state = yield select(getState(encrypted));\n // TODO: Use actual decryption implementation\n return parseJson(state);\n}\n\n/**\n * Get the implementation of the `getSnapState` hook.\n *\n * @param runSaga - The function to run a saga outside the usual Redux flow.\n * @returns The implementation of the `getSnapState` hook.\n */\nexport function getGetSnapStateMethodImplementation(runSaga: RunSagaFunction) {\n return (...args: Parameters<typeof getSnapStateImplementation>) => {\n return runSaga(getSnapStateImplementation, ...args).result();\n };\n}\n\n/**\n * Update the Snap state in the store.\n *\n * @param _snapId - The ID of the Snap to update the state for. This is ignored\n * because the simulator only supports one Snap.\n * @param newState - The new state.\n * @param encrypted - Whether to update the encrypted or unencrypted state.\n * Defaults to encrypted state.\n * @yields Puts the new state in the store.\n */\nfunction* updateSnapStateImplementation(\n _snapId: string,\n newState: Record<string, Json>,\n encrypted = true,\n): SagaIterator<void> {\n // TODO: Use actual encryption implementation\n yield put(setState({ state: JSON.stringify(newState), encrypted }));\n}\n\n/**\n * Get the implementation of the `updateSnapState` hook.\n *\n * @param runSaga - The function to run a saga outside the usual Redux flow.\n * @returns The implementation of the `updateSnapState` hook.\n */\nexport function getUpdateSnapStateMethodImplementation(\n runSaga: RunSagaFunction,\n) {\n return (...args: Parameters<typeof updateSnapStateImplementation>) => {\n runSaga(updateSnapStateImplementation, ...args).result();\n };\n}\n\n/**\n * Clear the Snap state in the store.\n *\n * @param _snapId - The ID of the Snap to clear the state for. This is ignored\n * because the simulator only supports one Snap.\n * @param encrypted - Whether to clear the encrypted or unencrypted state.\n * Defaults to encrypted state.\n * @yields Puts the new state in the store.\n */\nfunction* clearSnapStateImplementation(\n _snapId: string,\n encrypted = true,\n): SagaIterator<void> {\n yield put(clearState({ encrypted }));\n}\n\n/**\n * Get the implementation of the `clearSnapState` hook.\n *\n * @param runSaga - The function to run a saga outside the usual Redux flow.\n * @returns The implementation of the `clearSnapState` hook.\n */\nexport function getClearSnapStateMethodImplementation(\n runSaga: RunSagaFunction,\n) {\n return async (...args: Parameters<typeof clearSnapStateImplementation>) => {\n runSaga(clearSnapStateImplementation, ...args).result();\n };\n}\n"],"mappings":";;;;;;;AAAA,SAAS,iBAAiB;AAG1B,SAAS,KAAK,cAAc;AAe5B,UAAU,2BACR,SACA,YAAY,MACU;AACtB,QAAM,QAAQ,MAAM,OAAO,SAAS,SAAS,CAAC;AAE9C,SAAO,UAAU,KAAK;AACxB;AAQO,SAAS,oCAAoC,SAA0B;AAC5E,SAAO,IAAI,SAAwD;AACjE,WAAO,QAAQ,4BAA4B,GAAG,IAAI,EAAE,OAAO;AAAA,EAC7D;AACF;AAYA,UAAU,8BACR,SACA,UACA,YAAY,MACQ;AAEpB,QAAM,IAAI,SAAS,EAAE,OAAO,KAAK,UAAU,QAAQ,GAAG,UAAU,CAAC,CAAC;AACpE;AAQO,SAAS,uCACd,SACA;AACA,SAAO,IAAI,SAA2D;AACpE,YAAQ,+BAA+B,GAAG,IAAI,EAAE,OAAO;AAAA,EACzD;AACF;AAWA,UAAU,6BACR,SACA,YAAY,MACQ;AACpB,QAAM,IAAI,WAAW,EAAE,UAAU,CAAC,CAAC;AACrC;AAQO,SAAS,sCACd,SACA;AACA,SAAO,UAAU,SAA0D;AACzE,YAAQ,8BAA8B,GAAG,IAAI,EAAE,OAAO;AAAA,EACxD;AACF;","names":[]}
@@ -0,0 +1,127 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
+
3
+
4
+
5
+ var _chunkY4DKEF7Yjs = require('./chunk-Y4DKEF7Y.js');
6
+
7
+
8
+
9
+ var _chunk2YE2P5BZjs = require('./chunk-2YE2P5BZ.js');
10
+
11
+ // src/internals/request.ts
12
+ var _snapsutils = require('@metamask/snaps-utils');
13
+ var _utils = require('@metamask/utils');
14
+ var _toolkit = require('@reduxjs/toolkit');
15
+ function handleRequest({
16
+ snapId,
17
+ store,
18
+ executionService,
19
+ handler,
20
+ controllerMessenger,
21
+ runSaga,
22
+ request: { id = _toolkit.nanoid.call(void 0, ), origin = "https://metamask.io", ...options }
23
+ }) {
24
+ const promise = executionService.handleRpcRequest(snapId, {
25
+ origin,
26
+ handler,
27
+ request: {
28
+ jsonrpc: "2.0",
29
+ id: 1,
30
+ ...options
31
+ }
32
+ }).then(async (result) => {
33
+ const notifications = _chunk2YE2P5BZjs.getNotifications.call(void 0, store.getState());
34
+ store.dispatch(_chunk2YE2P5BZjs.clearNotifications.call(void 0, ));
35
+ const getInterfaceFn = await getInterfaceApi(
36
+ result,
37
+ snapId,
38
+ controllerMessenger
39
+ );
40
+ return {
41
+ id: String(id),
42
+ response: {
43
+ result: _utils.getSafeJson.call(void 0, result)
44
+ },
45
+ notifications,
46
+ ...getInterfaceFn ? { getInterface: getInterfaceFn } : {}
47
+ };
48
+ }).catch((error) => {
49
+ const [unwrappedError] = _snapsutils.unwrapError.call(void 0, error);
50
+ return {
51
+ id: String(id),
52
+ response: {
53
+ error: unwrappedError.serialize()
54
+ },
55
+ notifications: []
56
+ };
57
+ });
58
+ promise.getInterface = async () => {
59
+ return await runSaga(
60
+ _chunkY4DKEF7Yjs.getInterface,
61
+ runSaga,
62
+ snapId,
63
+ controllerMessenger
64
+ ).toPromise();
65
+ };
66
+ return promise;
67
+ }
68
+ async function getInterfaceFromResult(result, snapId, controllerMessenger) {
69
+ if (_utils.isPlainObject.call(void 0, result) && _utils.hasProperty.call(void 0, result, "id")) {
70
+ return result.id;
71
+ }
72
+ if (_utils.isPlainObject.call(void 0, result) && _utils.hasProperty.call(void 0, result, "content")) {
73
+ const id = await controllerMessenger.call(
74
+ "SnapInterfaceController:createInterface",
75
+ snapId,
76
+ result.content
77
+ );
78
+ return id;
79
+ }
80
+ return void 0;
81
+ }
82
+ async function getInterfaceApi(result, snapId, controllerMessenger) {
83
+ const interfaceId = await getInterfaceFromResult(
84
+ result,
85
+ snapId,
86
+ controllerMessenger
87
+ );
88
+ if (interfaceId) {
89
+ return () => {
90
+ const { content } = controllerMessenger.call(
91
+ "SnapInterfaceController:getInterface",
92
+ snapId,
93
+ interfaceId
94
+ );
95
+ return {
96
+ content,
97
+ clickElement: async (name) => {
98
+ await _chunkY4DKEF7Yjs.clickElement.call(void 0,
99
+ controllerMessenger,
100
+ interfaceId,
101
+ content,
102
+ snapId,
103
+ name
104
+ );
105
+ },
106
+ typeInField: async (name, value) => {
107
+ await _chunkY4DKEF7Yjs.typeInField.call(void 0,
108
+ controllerMessenger,
109
+ interfaceId,
110
+ content,
111
+ snapId,
112
+ name,
113
+ value
114
+ );
115
+ }
116
+ };
117
+ };
118
+ }
119
+ return void 0;
120
+ }
121
+
122
+
123
+
124
+
125
+
126
+ exports.handleRequest = handleRequest; exports.getInterfaceFromResult = getInterfaceFromResult; exports.getInterfaceApi = getInterfaceApi;
127
+ //# sourceMappingURL=chunk-6POKT4OO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/internals/request.ts"],"names":[],"mappings":";;;;;;;;;;;AAGA,SAAS,mBAAmB;AAC5B,SAAS,aAAa,aAAa,qBAAqB;AACxD,SAAS,cAAc;AA+ChB,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS,EAAE,KAAK,OAAO,GAAG,SAAS,uBAAuB,GAAG,QAAQ;AACvE,GAAsC;AACpC,QAAM,UAAU,iBACb,iBAAiB,QAAQ;AAAA,IACxB;AAAA,IACA;AAAA,IACA,SAAS;AAAA,MACP,SAAS;AAAA,MACT,IAAI;AAAA,MACJ,GAAG;AAAA,IACL;AAAA,EACF,CAAC,EACA,KAAK,OAAO,WAAW;AACtB,UAAM,gBAAgB,iBAAiB,MAAM,SAAS,CAAC;AACvD,UAAM,SAAS,mBAAmB,CAAC;AAEnC,UAAM,iBAAiB,MAAM;AAAA,MAC3B;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,WAAO;AAAA,MACL,IAAI,OAAO,EAAE;AAAA,MACb,UAAU;AAAA,QACR,QAAQ,YAAY,MAAM;AAAA,MAC5B;AAAA,MACA;AAAA,MACA,GAAI,iBAAiB,EAAE,cAAc,eAAe,IAAI,CAAC;AAAA,IAC3D;AAAA,EACF,CAAC,EACA,MAAM,CAAC,UAAU;AAChB,UAAM,CAAC,cAAc,IAAI,YAAY,KAAK;AAE1C,WAAO;AAAA,MACL,IAAI,OAAO,EAAE;AAAA,MACb,UAAU;AAAA,QACR,OAAO,eAAe,UAAU;AAAA,MAClC;AAAA,MACA,eAAe,CAAC;AAAA,IAClB;AAAA,EACF,CAAC;AAEH,UAAQ,eAAe,YAAY;AACjC,WAAO,MAAM;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,UAAU;AAAA,EACd;AAEA,SAAO;AACT;AAUA,eAAsB,uBACpB,QACA,QACA,qBACA;AACA,MAAI,cAAc,MAAM,KAAK,YAAY,QAAQ,IAAI,GAAG;AACtD,WAAO,OAAO;AAAA,EAChB;AAEA,MAAI,cAAc,MAAM,KAAK,YAAY,QAAQ,SAAS,GAAG;AAC3D,UAAM,KAAK,MAAM,oBAAoB;AAAA,MACnC;AAAA,MACA;AAAA,MACA,OAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAUA,eAAsB,gBACpB,QACA,QACA,qBACmD;AACnD,QAAM,cAAc,MAAM;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,MAAI,aAAa;AACf,WAAO,MAAM;AACX,YAAM,EAAE,QAAQ,IAAI,oBAAoB;AAAA,QACtC;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAEA,aAAO;AAAA,QACL;AAAA,QACA,cAAc,OAAO,SAAS;AAC5B,gBAAM;AAAA,YACJ;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,QACA,aAAa,OAAO,MAAM,UAAU;AAClC,gBAAM;AAAA,YACJ;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT","sourcesContent":["import type { AbstractExecutionService } from '@metamask/snaps-controllers';\nimport type { SnapId, Component } from '@metamask/snaps-sdk';\nimport type { HandlerType } from '@metamask/snaps-utils';\nimport { unwrapError } from '@metamask/snaps-utils';\nimport { getSafeJson, hasProperty, isPlainObject } from '@metamask/utils';\nimport { nanoid } from '@reduxjs/toolkit';\n\nimport type {\n RequestOptions,\n SnapHandlerInterface,\n SnapRequest,\n} from '../types';\nimport {\n clearNotifications,\n clickElement,\n getInterface,\n getNotifications,\n typeInField,\n} from './simulation';\nimport type { RunSagaFunction, Store } from './simulation';\nimport type { RootControllerMessenger } from './simulation/controllers';\n\nexport type HandleRequestOptions = {\n snapId: SnapId;\n store: Store;\n executionService: AbstractExecutionService<unknown>;\n handler: HandlerType;\n controllerMessenger: RootControllerMessenger;\n runSaga: RunSagaFunction;\n request: RequestOptions;\n};\n\n/**\n * Send a JSON-RPC request to the Snap, and wrap the response in a\n * {@link SnapResponse} object.\n *\n * @param options - The request options.\n * @param options.snapId - The ID of the Snap to send the request to.\n * @param options.store - The Redux store.\n * @param options.executionService - The execution service to use to send the\n * request.\n * @param options.handler - The handler to use to send the request.\n * @param options.controllerMessenger - The controller messenger used to call actions.\n * @param options.runSaga - A function to run a saga outside the usual Redux\n * flow.\n * @param options.request - The request to send.\n * @param options.request.id - The ID of the request. If not provided, a random\n * ID will be generated.\n * @param options.request.origin - The origin of the request. Defaults to\n * `https://metamask.io`.\n * @returns The response, wrapped in a {@link SnapResponse} object.\n */\nexport function handleRequest({\n snapId,\n store,\n executionService,\n handler,\n controllerMessenger,\n runSaga,\n request: { id = nanoid(), origin = 'https://metamask.io', ...options },\n}: HandleRequestOptions): SnapRequest {\n const promise = executionService\n .handleRpcRequest(snapId, {\n origin,\n handler,\n request: {\n jsonrpc: '2.0',\n id: 1,\n ...options,\n },\n })\n .then(async (result) => {\n const notifications = getNotifications(store.getState());\n store.dispatch(clearNotifications());\n\n const getInterfaceFn = await getInterfaceApi(\n result,\n snapId,\n controllerMessenger,\n );\n\n return {\n id: String(id),\n response: {\n result: getSafeJson(result),\n },\n notifications,\n ...(getInterfaceFn ? { getInterface: getInterfaceFn } : {}),\n };\n })\n .catch((error) => {\n const [unwrappedError] = unwrapError(error);\n\n return {\n id: String(id),\n response: {\n error: unwrappedError.serialize(),\n },\n notifications: [],\n };\n }) as unknown as SnapRequest;\n\n promise.getInterface = async () => {\n return await runSaga(\n getInterface,\n runSaga,\n snapId,\n controllerMessenger,\n ).toPromise();\n };\n\n return promise;\n}\n\n/**\n * Get the interface ID from the result if it's available or create a new interface if the result contains static components.\n *\n * @param result - The handler result object.\n * @param snapId - The Snap ID.\n * @param controllerMessenger - The controller messenger.\n * @returns The interface ID or undefined if the result doesn't include content.\n */\nexport async function getInterfaceFromResult(\n result: unknown,\n snapId: SnapId,\n controllerMessenger: RootControllerMessenger,\n) {\n if (isPlainObject(result) && hasProperty(result, 'id')) {\n return result.id as string;\n }\n\n if (isPlainObject(result) && hasProperty(result, 'content')) {\n const id = await controllerMessenger.call(\n 'SnapInterfaceController:createInterface',\n snapId,\n result.content as Component,\n );\n\n return id;\n }\n\n return undefined;\n}\n\n/**\n * Get the response content from the SnapInterfaceController and include the interaction methods.\n *\n * @param result - The handler result object.\n * @param snapId - The Snap ID.\n * @param controllerMessenger - The controller messenger.\n * @returns The content components if any.\n */\nexport async function getInterfaceApi(\n result: unknown,\n snapId: SnapId,\n controllerMessenger: RootControllerMessenger,\n): Promise<(() => SnapHandlerInterface) | undefined> {\n const interfaceId = await getInterfaceFromResult(\n result,\n snapId,\n controllerMessenger,\n );\n\n if (interfaceId) {\n return () => {\n const { content } = controllerMessenger.call(\n 'SnapInterfaceController:getInterface',\n snapId,\n interfaceId,\n );\n\n return {\n content,\n clickElement: async (name) => {\n await clickElement(\n controllerMessenger,\n interfaceId,\n content,\n snapId,\n name,\n );\n },\n typeInField: async (name, value) => {\n await typeInField(\n controllerMessenger,\n interfaceId,\n content,\n snapId,\n name,\n value,\n );\n },\n };\n };\n }\n\n return undefined;\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  InterfaceStruct,
3
3
  SnapResponseStruct
4
- } from "./chunk-7J34R6YW.mjs";
4
+ } from "./chunk-YEVKBYKO.mjs";
5
5
 
6
6
  // src/matchers.ts
7
7
  import { expect } from "@jest/globals";
@@ -131,4 +131,4 @@ export {
131
131
  toSendNotification,
132
132
  toRender
133
133
  };
134
- //# sourceMappingURL=chunk-7VILST6M.mjs.map
134
+ //# sourceMappingURL=chunk-BVGI3E45.mjs.map
@@ -0,0 +1 @@
1
+ "use strict";//# sourceMappingURL=chunk-CKRORVDW.js.map
@@ -1,6 +1,6 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
- var _chunkLXSNRZV4js = require('./chunk-LXSNRZV4.js');
3
+ var _chunkZWN4SO2Vjs = require('./chunk-ZWN4SO2V.js');
4
4
 
5
5
 
6
6
  var _chunkXAOCS6ZDjs = require('./chunk-XAOCS6ZD.js');
@@ -47,7 +47,7 @@ function getControllers(options) {
47
47
  }
48
48
  function getPermissionController(options) {
49
49
  const { controllerMessenger } = options;
50
- const permissionSpecifications = _chunkLXSNRZV4js.getPermissionSpecifications.call(void 0, options);
50
+ const permissionSpecifications = _chunkZWN4SO2Vjs.getPermissionSpecifications.call(void 0, options);
51
51
  return new (0, _permissioncontroller.PermissionController)({
52
52
  messenger: controllerMessenger.getRestricted({
53
53
  name: "PermissionController",
@@ -92,4 +92,4 @@ async function registerSnap(snapId, manifest, {
92
92
 
93
93
 
94
94
  exports.getControllers = getControllers; exports.registerSnap = registerSnap;
95
- //# sourceMappingURL=chunk-6HW5NGCB.js.map
95
+ //# sourceMappingURL=chunk-DTDYOBCI.js.map
@@ -1,25 +1,26 @@
1
+ import {
2
+ getEnvironment
3
+ } from "./chunk-XK5HPZZC.mjs";
1
4
  import {
2
5
  handleRequest
3
- } from "./chunk-LYK6EGZU.mjs";
6
+ } from "./chunk-PVMIH6OB.mjs";
4
7
  import {
5
8
  rootLogger
6
9
  } from "./chunk-J4ZPUCLX.mjs";
7
10
  import {
8
11
  JsonRpcMockOptionsStruct,
9
12
  SignatureOptionsStruct,
13
+ SnapResponseWithInterfaceStruct,
10
14
  TransactionOptionsStruct
11
- } from "./chunk-7J34R6YW.mjs";
15
+ } from "./chunk-YEVKBYKO.mjs";
12
16
  import {
13
17
  addJsonRpcMock,
14
18
  removeJsonRpcMock
15
19
  } from "./chunk-H2464AXT.mjs";
16
- import {
17
- getEnvironment
18
- } from "./chunk-XK5HPZZC.mjs";
19
20
 
20
21
  // src/helpers.ts
21
22
  import { HandlerType, logInfo } from "@metamask/snaps-utils";
22
- import { createModuleLogger } from "@metamask/utils";
23
+ import { assertStruct, createModuleLogger } from "@metamask/utils";
23
24
  import { create } from "superstruct";
24
25
  var log = createModuleLogger(rootLogger, "helpers");
25
26
  function getOptions(snapId, options) {
@@ -28,6 +29,9 @@ function getOptions(snapId, options) {
28
29
  }
29
30
  return [snapId, options];
30
31
  }
32
+ function assertIsResponseWithInterface(response) {
33
+ assertStruct(response, SnapResponseWithInterfaceStruct);
34
+ }
31
35
  async function installSnap(snapId, options = {}) {
32
36
  const resolvedOptions = getOptions(snapId, options);
33
37
  const {
@@ -44,7 +48,7 @@ async function installSnap(snapId, options = {}) {
44
48
  chainId,
45
49
  ...transaction
46
50
  } = create(request, TransactionOptionsStruct);
47
- return handleRequest({
51
+ const response = await handleRequest({
48
52
  snapId: installedSnapId,
49
53
  store,
50
54
  executionService,
@@ -60,6 +64,8 @@ async function installSnap(snapId, options = {}) {
60
64
  }
61
65
  }
62
66
  });
67
+ assertIsResponseWithInterface(response);
68
+ return response;
63
69
  };
64
70
  const onCronjob = (request) => {
65
71
  log("Running cronjob %o.", options);
@@ -94,7 +100,7 @@ async function installSnap(snapId, options = {}) {
94
100
  request,
95
101
  SignatureOptionsStruct
96
102
  );
97
- return handleRequest({
103
+ const response = await handleRequest({
98
104
  snapId: installedSnapId,
99
105
  store,
100
106
  executionService,
@@ -109,12 +115,14 @@ async function installSnap(snapId, options = {}) {
109
115
  }
110
116
  }
111
117
  });
118
+ assertIsResponseWithInterface(response);
119
+ return response;
112
120
  },
113
121
  onCronjob,
114
122
  runCronjob: onCronjob,
115
123
  onHomePage: async () => {
116
124
  log("Rendering home page.");
117
- return handleRequest({
125
+ const response = await handleRequest({
118
126
  snapId: installedSnapId,
119
127
  store,
120
128
  executionService,
@@ -125,6 +133,8 @@ async function installSnap(snapId, options = {}) {
125
133
  method: ""
126
134
  }
127
135
  });
136
+ assertIsResponseWithInterface(response);
137
+ return response;
128
138
  },
129
139
  mockJsonRpc(mock) {
130
140
  log("Mocking JSON-RPC request %o.", mock);
@@ -150,4 +160,4 @@ async function installSnap(snapId, options = {}) {
150
160
  export {
151
161
  installSnap
152
162
  };
153
- //# sourceMappingURL=chunk-WIFOID2P.mjs.map
163
+ //# sourceMappingURL=chunk-EDEJD326.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/helpers.ts"],"sourcesContent":["import type { AbstractExecutionService } from '@metamask/snaps-controllers';\nimport type { SnapId } from '@metamask/snaps-sdk';\nimport { HandlerType, logInfo } from '@metamask/snaps-utils';\nimport { assertStruct, createModuleLogger } from '@metamask/utils';\nimport { create } from 'superstruct';\n\nimport {\n rootLogger,\n handleRequest,\n TransactionOptionsStruct,\n getEnvironment,\n JsonRpcMockOptionsStruct,\n SignatureOptionsStruct,\n SnapResponseWithInterfaceStruct,\n} from './internals';\nimport type { InstallSnapOptions } from './internals';\nimport {\n addJsonRpcMock,\n removeJsonRpcMock,\n} from './internals/simulation/store/mocks';\nimport type {\n SnapResponseWithInterface,\n CronjobOptions,\n JsonRpcMockOptions,\n Snap,\n SnapResponse,\n TransactionOptions,\n} from './types';\n\nconst log = createModuleLogger(rootLogger, 'helpers');\n\n/**\n * Get the options for {@link installSnap}.\n *\n * @param snapId - The ID of the Snap, or the options.\n * @param options - The options, if any.\n * @returns The options.\n */\nfunction getOptions<\n Service extends new (...args: any[]) => InstanceType<\n typeof AbstractExecutionService\n >,\n>(\n snapId: SnapId | Partial<InstallSnapOptions<Service>> | undefined,\n options: Partial<InstallSnapOptions<Service>>,\n): [SnapId | undefined, Partial<InstallSnapOptions<Service>>] {\n if (typeof snapId === 'object') {\n return [undefined, snapId];\n }\n\n return [snapId, options];\n}\n\n/**\n * Ensure that the actual response contains `getInterface`.\n *\n * @param response - The response of the handler.\n */\nfunction assertIsResponseWithInterface(\n response: SnapResponse,\n): asserts response is SnapResponseWithInterface {\n assertStruct(response, SnapResponseWithInterfaceStruct);\n}\n\n/**\n * Load a snap into the environment. This is the main entry point for testing\n * snaps: It returns a {@link Snap} object that can be used to interact with the\n * snap.\n *\n * @example\n * import { installSnap } from '@metamask/snaps-jest';\n *\n * describe('My Snap', () => {\n * it('should do something', async () => {\n * const { request } = await installSnap('local:my-snap');\n * const response = await request({\n * method: 'foo',\n * params: ['bar'],\n * });\n * expect(response).toRespondWith('bar');\n * });\n * });\n * @returns The snap.\n * @throws If the built-in server is not running, and no snap ID is provided.\n */\nexport async function installSnap(): Promise<Snap>;\n\n/**\n * Load a snap into the environment. This is the main entry point for testing\n * snaps: It returns a {@link Snap} object that can be used to interact with the\n * snap.\n *\n * @example\n * import { installSnap } from '@metamask/snaps-jest';\n *\n * describe('My Snap', () => {\n * it('should do something', async () => {\n * const { request } = await installSnap('local:my-snap');\n * const response = await request({\n * method: 'foo',\n * params: ['bar'],\n * });\n * expect(response).toRespondWith('bar');\n * });\n * });\n * @param options - The options to use.\n * @param options.executionService - The execution service to use. Defaults to\n * {@link NodeThreadExecutionService}. You do not need to provide this unless\n * you are testing a custom execution service.\n * @param options.executionServiceOptions - The options to use when creating the\n * execution service, if any. This should only include options specific to the\n * provided execution service.\n * @param options.options - The simulation options.\n * @returns The snap.\n * @throws If the built-in server is not running, and no snap ID is provided.\n */\nexport async function installSnap<\n Service extends new (...args: any[]) => InstanceType<\n typeof AbstractExecutionService\n >,\n>(options: Partial<InstallSnapOptions<Service>>): Promise<Snap>;\n\n/**\n * Load a snap into the environment. This is the main entry point for testing\n * snaps: It returns a {@link Snap} object that can be used to interact with the\n * snap.\n *\n * @example\n * import { installSnap } from '@metamask/snaps-jest';\n *\n * describe('My Snap', () => {\n * it('should do something', async () => {\n * const { request } = await installSnap('local:my-snap');\n * const response = await request({\n * method: 'foo',\n * params: ['bar'],\n * });\n * expect(response).toRespondWith('bar');\n * });\n * });\n * @param snapId - The ID of the snap, including the prefix (`local:`). Defaults\n * to the URL of the built-in server, if it is running. This supports both\n * local snap IDs and NPM snap IDs.\n * @param options - The options to use.\n * @param options.executionService - The execution service to use. Defaults to\n * {@link NodeThreadExecutionService}. You do not need to provide this unless\n * you are testing a custom execution service.\n * @param options.executionServiceOptions - The options to use when creating the\n * execution service, if any. This should only include options specific to the\n * provided execution service.\n * @param options.options - The simulation options.\n * @returns The snap.\n * @throws If the built-in server is not running, and no snap ID is provided.\n */\nexport async function installSnap<\n Service extends new (...args: any[]) => InstanceType<\n typeof AbstractExecutionService\n >,\n>(\n snapId: SnapId,\n options?: Partial<InstallSnapOptions<Service>>,\n): Promise<Snap>;\n\n/**\n * Load a snap into the environment. This is the main entry point for testing\n * snaps: It returns a {@link Snap} object that can be used to interact with the\n * snap.\n *\n * @example\n * import { installSnap } from '@metamask/snaps-jest';\n *\n * describe('My Snap', () => {\n * it('should do something', async () => {\n * const { request } = await installSnap('local:my-snap');\n * const response = await request({\n * method: 'foo',\n * params: ['bar'],\n * });\n * expect(response).toRespondWith('bar');\n * });\n * });\n * @param snapId - The ID of the snap, including the prefix (`local:`). Defaults\n * to the URL of the built-in server, if it is running. This supports both\n * local snap IDs and NPM snap IDs.\n * @param options - The options to use.\n * @param options.executionService - The execution service to use. Defaults to\n * {@link NodeThreadExecutionService}. You do not need to provide this unless\n * you are testing a custom execution service.\n * @param options.executionServiceOptions - The options to use when creating the\n * execution service, if any. This should only include options specific to the\n * provided execution service.\n * @param options.options - The simulation options.\n * @returns The snap.\n * @throws If the built-in server is not running, and no snap ID is provided.\n */\nexport async function installSnap<\n Service extends new (...args: any[]) => InstanceType<\n typeof AbstractExecutionService\n >,\n>(\n snapId?: SnapId | Partial<InstallSnapOptions<Service>>,\n options: Partial<InstallSnapOptions<Service>> = {},\n): Promise<Snap> {\n const resolvedOptions = getOptions(snapId, options);\n const {\n snapId: installedSnapId,\n store,\n executionService,\n runSaga,\n controllerMessenger,\n } = await getEnvironment().installSnap(...resolvedOptions);\n\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: installedSnapId,\n store,\n executionService,\n runSaga,\n controllerMessenger,\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 const onCronjob = (request: CronjobOptions) => {\n log('Running cronjob %o.', options);\n\n return handleRequest({\n snapId: installedSnapId,\n store,\n executionService,\n controllerMessenger,\n runSaga,\n handler: HandlerType.OnCronjob,\n request,\n });\n };\n\n return {\n request: (request) => {\n log('Sending request %o.', request);\n\n return handleRequest({\n snapId: installedSnapId,\n store,\n executionService,\n controllerMessenger,\n runSaga,\n handler: HandlerType.OnRpcRequest,\n request,\n });\n },\n\n onTransaction,\n sendTransaction: onTransaction,\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: installedSnapId,\n store,\n executionService,\n controllerMessenger,\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\n onHomePage: async (): Promise<SnapResponseWithInterface> => {\n log('Rendering home page.');\n\n const response = await handleRequest({\n snapId: installedSnapId,\n store,\n executionService,\n controllerMessenger,\n runSaga,\n handler: HandlerType.OnHomePage,\n request: {\n method: '',\n },\n });\n\n assertIsResponseWithInterface(response);\n\n return response;\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 logInfo(\n 'Calling `snap.close()` is deprecated, and will be removed in a future release. Snaps are now automatically closed when the test ends.',\n );\n\n await executionService.terminateAllSnaps();\n },\n };\n}\n"],"mappings":"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","names":[]}
@@ -1,7 +1,7 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
3
 
4
- var _chunkT2BE4O5Hjs = require('./chunk-T2BE4O5H.js');
4
+ var _chunkIDGD7TZ7js = require('./chunk-IDGD7TZ7.js');
5
5
 
6
6
  // src/matchers.ts
7
7
  var _globals = require('@jest/globals');
@@ -16,7 +16,7 @@ var _utils = require('@metamask/utils');
16
16
  var _jestmatcherutils = require('jest-matcher-utils');
17
17
  var _superstruct = require('superstruct');
18
18
  function assertActualIsSnapResponse(actual, matcherName, options) {
19
- if (!_superstruct.is.call(void 0, actual, _chunkT2BE4O5Hjs.SnapResponseStruct)) {
19
+ if (!_superstruct.is.call(void 0, actual, _chunkIDGD7TZ7js.SnapResponseStruct)) {
20
20
  throw new Error(
21
21
  _jestmatcherutils.matcherErrorMessage.call(void 0,
22
22
  _jestmatcherutils.matcherHint.call(void 0, matcherName, void 0, void 0, options),
@@ -29,7 +29,7 @@ function assertActualIsSnapResponse(actual, matcherName, options) {
29
29
  }
30
30
  }
31
31
  function assertHasInterface(actual, matcherName, options) {
32
- if (!_superstruct.is.call(void 0, actual, _chunkT2BE4O5Hjs.InterfaceStruct) || !actual.content) {
32
+ if (!_superstruct.is.call(void 0, actual, _chunkIDGD7TZ7js.InterfaceStruct) || !actual.content) {
33
33
  throw new Error(
34
34
  _jestmatcherutils.matcherErrorMessage.call(void 0,
35
35
  _jestmatcherutils.matcherHint.call(void 0, matcherName, void 0, void 0, options),
@@ -131,4 +131,4 @@ _globals.expect.extend({
131
131
 
132
132
 
133
133
  exports.toRespondWith = toRespondWith; exports.toRespondWithError = toRespondWithError; exports.toSendNotification = toSendNotification; exports.toRender = toRender;
134
- //# sourceMappingURL=chunk-B4QZXXQY.js.map
134
+ //# sourceMappingURL=chunk-FIZAYEHV.js.map