From 61159313b5573701e1afac0391b6daaf3aabdf88 Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Mon, 11 Aug 2025 14:24:37 +0200 Subject: [PATCH 1/2] test: Use newer example Snap as NPM fixture --- packages/snaps-controllers/package.json | 1 - .../src/snaps/location/npm.test.ts | 215 +++++++++--------- .../metamask-jsx-example-snap-1.2.1.tgz | Bin 0 -> 11962 bytes .../fixtures/metamask-template-snap-0.7.0.tgz | Bin 5477 -> 0 bytes yarn.lock | 8 - 5 files changed, 108 insertions(+), 116 deletions(-) create mode 100644 packages/snaps-controllers/test/fixtures/metamask-jsx-example-snap-1.2.1.tgz delete mode 100644 packages/snaps-controllers/test/fixtures/metamask-template-snap-0.7.0.tgz diff --git a/packages/snaps-controllers/package.json b/packages/snaps-controllers/package.json index 3f7a9c5b57..98028669ce 100644 --- a/packages/snaps-controllers/package.json +++ b/packages/snaps-controllers/package.json @@ -112,7 +112,6 @@ "@lavamoat/allow-scripts": "^3.3.4", "@metamask/auto-changelog": "^5.0.2", "@metamask/browser-passworder": "^6.0.0", - "@metamask/template-snap": "^0.7.0", "@noble/hashes": "^1.7.1", "@swc/core": "1.11.31", "@swc/jest": "^0.2.38", diff --git a/packages/snaps-controllers/src/snaps/location/npm.test.ts b/packages/snaps-controllers/src/snaps/location/npm.test.ts index 9d42d0bce4..a898b932ea 100644 --- a/packages/snaps-controllers/src/snaps/location/npm.test.ts +++ b/packages/snaps-controllers/src/snaps/location/npm.test.ts @@ -1,7 +1,5 @@ import type { SemVerRange } from '@metamask/utils'; -import { assert } from '@metamask/utils'; import { createReadStream } from 'fs'; -import { readFile } from 'fs/promises'; import fetchMock from 'jest-fetch-mock'; import path from 'path'; import { Readable } from 'stream'; @@ -14,20 +12,16 @@ import { fetchMock.enableMocks(); +const exampleSnapVersion = '1.2.1' as SemVerRange; + describe('NpmLocation', () => { beforeEach(() => { fetchMock.resetMocks(); }); it('fetches a package tarball, extracts the necessary files, and validates them', async () => { - const { version: templateSnapVersion } = JSON.parse( - ( - await readFile(require.resolve('@metamask/template-snap/package.json')) - ).toString('utf8'), - ); - - const tarballUrl = `https://registry.npmjs.cf/@metamask/template-snap/-/template-snap-${templateSnapVersion}.tgz`; - const tarballRegistry = `https://registry.npmjs.org/@metamask/template-snap/-/template-snap-${templateSnapVersion}.tgz`; + const tarballUrl = `https://registry.npmjs.cf/@metamask/jsx-example-snap/-/jsx-example-snap-${exampleSnapVersion}.tgz`; + const tarballRegistry = `https://registry.npmjs.org/@metamask/jsx-example-snap/-/jsx-example-snap-${exampleSnapVersion}.tgz`; const customFetchMock = jest.fn(); @@ -36,10 +30,10 @@ describe('NpmLocation', () => { ok: true, json: async () => ({ 'dist-tags': { - latest: templateSnapVersion, + latest: exampleSnapVersion, }, versions: { - [templateSnapVersion]: { + [exampleSnapVersion]: { dist: { // return npmjs.org registry here so that we can check overriding it with npmjs.cf works tarball: tarballRegistry, @@ -56,16 +50,16 @@ describe('NpmLocation', () => { createReadStream( path.resolve( __dirname, - `../../../test/fixtures/metamask-template-snap-${templateSnapVersion}.tgz`, + `../../../test/fixtures/metamask-jsx-example-snap-${exampleSnapVersion}.tgz`, ), ), ), } as any); const location = new NpmLocation( - new URL('npm://registry.npmjs.cf/@metamask/template-snap'), + new URL('npm://registry.npmjs.cf/@metamask/jsx-example-snap'), { - versionRange: templateSnapVersion, + versionRange: exampleSnapVersion, fetch: customFetchMock as typeof fetch, allowCustomRegistries: true, }, @@ -74,60 +68,62 @@ describe('NpmLocation', () => { const manifest = await location.manifest(); expect(manifest.path).toBe('snap.manifest.json'); expect(manifest.data.canonicalPath).toBe( - 'npm://registry.npmjs.cf/@metamask/template-snap/snap.manifest.json', + 'npm://registry.npmjs.cf/@metamask/jsx-example-snap/snap.manifest.json', ); const sourceCode = await location.fetch( manifest.result.source.location.npm.filePath, ); expect(sourceCode.path).toBe('dist/bundle.js'); expect(sourceCode.data.canonicalPath).toBe( - 'npm://registry.npmjs.cf/@metamask/template-snap/dist/bundle.js', + 'npm://registry.npmjs.cf/@metamask/jsx-example-snap/dist/bundle.js', ); - assert(manifest.result.source.location.npm.iconPath); - const svgIcon = ( - await location.fetch(manifest.result.source.location.npm.iconPath) - ).toString(); expect(customFetchMock).toHaveBeenCalledTimes(2); expect(customFetchMock).toHaveBeenNthCalledWith( 1, - 'https://registry.npmjs.cf/@metamask/template-snap', + 'https://registry.npmjs.cf/@metamask/jsx-example-snap', { headers: { accept: 'application/json' } }, ); expect(customFetchMock).toHaveBeenNthCalledWith(2, tarballUrl); - expect(manifest.result).toStrictEqual( - JSON.parse( - ( - await readFile( - require.resolve('@metamask/template-snap/snap.manifest.json'), - ) - ).toString('utf8'), - ), - ); - - expect(sourceCode.toString()).toStrictEqual( - ( - await readFile( - require.resolve('@metamask/template-snap/dist/bundle.js'), - ) - ).toString('utf8'), - ); + expect(manifest.result).toMatchInlineSnapshot(` + { + "description": "MetaMask example snap demonstrating the use of JSX for UI components.", + "initialPermissions": { + "endowment:rpc": { + "dapps": true, + }, + "snap_dialog": {}, + "snap_manageState": {}, + }, + "manifestVersion": "0.1", + "proposedName": "JSX Example Snap", + "repository": { + "type": "git", + "url": "https://github.com/MetaMask/snaps.git", + }, + "source": { + "location": { + "npm": { + "filePath": "dist/bundle.js", + "packageName": "@metamask/jsx-example-snap", + "registry": "https://registry.npmjs.org/", + }, + }, + "shasum": "3U9+Lvmmdc9JRmaHLcwGgi9lpnaj25joBF9+zXY4644=", + }, + "version": "1.2.1", + } + `); - expect(svgIcon?.startsWith('')).toBe( - true, + expect(sourceCode.toString()).toMatchInlineSnapshot( + `"(()=>{var e={12:e=>{e.exports=a,a.default=a,a.stable=d,a.stableStringify=d;var t="[...]",n="[Circular]",r=[],o=[];function i(){return{depthLimit:Number.MAX_SAFE_INTEGER,edgesLimit:Number.MAX_SAFE_INTEGER}}function a(e,t,n,a){var s;void 0===a&&(a=i()),c(e,"",0,[],void 0,0,a);try{s=0===o.length?JSON.stringify(e,t,n):JSON.stringify(e,l(t),n)}catch(e){return JSON.stringify("[unable to serialize, circular reference is too complex to analyze]")}finally{for(;0!==r.length;){var u=r.pop();4===u.length?Object.defineProperty(u[0],u[1],u[3]):u[0][u[1]]=u[2]}}return s}function s(e,t,n,i){var a=Object.getOwnPropertyDescriptor(i,n);void 0!==a.get?a.configurable?(Object.defineProperty(i,n,{value:e}),r.push([i,n,t,a])):o.push([t,n,e]):(i[n]=e,r.push([i,n,t]))}function c(e,r,o,i,a,u,d){var f;if(u+=1,"object"==typeof e&&null!==e){for(f=0;fd.depthLimit)return void s(t,e,r,a);if(void 0!==d.edgesLimit&&o+1>d.edgesLimit)return void s(t,e,r,a);if(i.push(e),Array.isArray(e))for(f=0;ft?1:0}function d(e,t,n,a){void 0===a&&(a=i());var s,c=f(e,"",0,[],void 0,0,a)||e;try{s=0===o.length?JSON.stringify(c,t,n):JSON.stringify(c,l(t),n)}catch(e){return JSON.stringify("[unable to serialize, circular reference is too complex to analyze]")}finally{for(;0!==r.length;){var u=r.pop();4===u.length?Object.defineProperty(u[0],u[1],u[3]):u[0][u[1]]=u[2]}}return s}function f(e,o,i,a,c,d,l){var p;if(d+=1,"object"==typeof e&&null!==e){for(p=0;pl.depthLimit)return void s(t,e,o,c);if(void 0!==l.edgesLimit&&i+1>l.edgesLimit)return void s(t,e,o,c);if(a.push(e),Array.isArray(e))for(p=0;p0)for(var r=0;r{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var r={};(()=>{"use strict";function e(e,t,n){if("string"==typeof e)throw new Error(\`An HTML element ("\${String(e)}") was used in a Snap component, which is not supported by Snaps UI. Please use one of the supported Snap components.\`);if(!e)throw new Error("A JSX fragment was used in a Snap component, which is not supported by Snaps UI. Please use one of the supported Snap components.");return e({...t,key:n})}function t(t,n,r){return e(t,n,r)}n.r(r),n.d(r,{onRpcRequest:()=>xe,onUserInput:()=>Ae});var o={invalidInput:-32e3,resourceNotFound:-32001,resourceUnavailable:-32002,transactionRejected:-32003,methodNotSupported:-32004,limitExceeded:-32005,parse:-32700,invalidRequest:-32600,methodNotFound:-32601,invalidParams:-32602,internal:-32603},i={"-32700":{standard:"JSON RPC 2.0",message:"Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text."},"-32600":{standard:"JSON RPC 2.0",message:"The JSON sent is not a valid Request object."},"-32601":{standard:"JSON RPC 2.0",message:"The method does not exist / is not available."},"-32602":{standard:"JSON RPC 2.0",message:"Invalid method parameter(s)."},"-32603":{standard:"JSON RPC 2.0",message:"Internal JSON-RPC error."},"-32000":{standard:"EIP-1474",message:"Invalid input."},"-32001":{standard:"EIP-1474",message:"Resource not found."},"-32002":{standard:"EIP-1474",message:"Resource unavailable."},"-32003":{standard:"EIP-1474",message:"Transaction rejected."},"-32004":{standard:"EIP-1474",message:"Method not supported."},"-32005":{standard:"EIP-1474",message:"Request limit exceeded."},4001:{standard:"EIP-1193",message:"User rejected the request."},4100:{standard:"EIP-1193",message:"The requested account and/or method has not been authorized by the user."},4200:{standard:"EIP-1193",message:"The requested method is not supported by this Ethereum provider."},4900:{standard:"EIP-1193",message:"The provider is disconnected from all chains."},4901:{standard:"EIP-1193",message:"The provider is disconnected from the specified chain."}};function a(e){return Boolean(e)&&"object"==typeof e&&!Array.isArray(e)}const s=(e,t)=>Object.hasOwnProperty.call(e,t);var c;!function(e){e[e.Null=4]="Null",e[e.Comma=1]="Comma",e[e.Wrapper=1]="Wrapper",e[e.True=4]="True",e[e.False=5]="False",e[e.Quote=1]="Quote",e[e.Colon=1]="Colon",e[e.Date=24]="Date"}(c=c||(c={}));class u extends TypeError{constructor(e,t){let n;const{message:r,explanation:o,...i}=e,{path:a}=e,s=0===a.length?r:\`At path: \${a.join(".")} -- \${r}\`;super(o??s),null!=o&&(this.cause=s),Object.assign(this,i),this.name=this.constructor.name,this.failures=()=>n??(n=[e,...t()])}}function d(e){return"object"==typeof e&&null!==e}function f(e){return"symbol"==typeof e?e.toString():"string"==typeof e?JSON.stringify(e):\`\${e}\`}function l(e,t,n,r){if(!0===e)return;!1===e?e={}:"string"==typeof e&&(e={message:e});const{path:o,branch:i}=t,{type:a}=n,{refinement:s,message:c=\`Expected a value of type \\\`\${a}\\\`\${s?\` with refinement \\\`\${s}\\\`\`:""}, but received: \\\`\${f(r)}\\\`\`}=e;return{value:r,type:a,refinement:s,key:o[o.length-1],path:o,branch:i,...e,message:c}}function*p(e,t,n,r){(function(e){return d(e)&&"function"==typeof e[Symbol.iterator]})(e)||(e=[e]);for(const o of e){const e=l(o,t,n,r);e&&(yield e)}}function*m(e,t,n={}){const{path:r=[],branch:o=[e],coerce:i=!1,mask:a=!1}=n,s={path:r,branch:o};if(i&&(e=t.coercer(e,s),a&&"type"!==t.type&&d(t.schema)&&d(e)&&!Array.isArray(e)))for(const n in e)void 0===t.schema[n]&&delete e[n];let c="valid";for(const r of t.validator(e,s))r.explanation=n.message,c="not_valid",yield[r,void 0];for(let[u,f,l]of t.entries(e,s)){const t=m(f,l,{path:void 0===u?r:[...r,u],branch:void 0===u?o:[...o,f],coerce:i,mask:a,message:n.message});for(const n of t)n[0]?(c=null===n[0].refinement||void 0===n[0].refinement?"not_valid":"not_refined",yield[n[0],void 0]):i&&(f=n[1],void 0===u?e=f:e instanceof Map?e.set(u,f):e instanceof Set?e.add(f):d(e)&&(void 0!==f||u in e)&&(e[u]=f))}if("not_valid"!==c)for(const r of t.refiner(e,s))r.explanation=n.message,c="not_refined",yield[r,void 0];"valid"===c&&(yield[void 0,e])}class h{constructor(e){const{type:t,schema:n,validator:r,refiner:o,coercer:i=(e=>e),entries:a=function*(){}}=e;this.type=t,this.schema=n,this.entries=a,this.coercer=i,this.validator=r?(e,t)=>p(r(e,t),t,this,e):()=>[],this.refiner=o?(e,t)=>p(o(e,t),t,this,e):()=>[]}assert(e,t){return y(e,this,t)}create(e,t){return v(e,this,t)}is(e){return g(e,this)}mask(e,t){return function(e,t,n){const r=b(e,t,{coerce:!0,mask:!0,message:n});if(r[0])throw r[0];return r[1]}(e,this,t)}validate(e,t={}){return b(e,this,t)}}function y(e,t,n){const r=b(e,t,{message:n});if(r[0])throw r[0]}function v(e,t,n){const r=b(e,t,{coerce:!0,message:n});if(r[0])throw r[0];return r[1]}function g(e,t){return!b(e,t)[0]}function b(e,t,n={}){const r=m(e,t,n),o=function(e){const{done:t,value:n}=e.next();return t?void 0:n}(r);if(o[0]){return[new u(o[0],(function*(){for(const e of r)e[0]&&(yield e[0])})),void 0]}return[void 0,o[1]]}function E(...e){const t="type"===e[0]?.type,n=e.map((({schema:e})=>e)),r=Object.assign({},...n);return t?function(e){const t=Object.keys(e);return new h({type:"type",schema:e,*entries(n){if(d(n))for(const r of t)yield[r,n[r],e[r]]},validator:e=>d(e)||\`Expected an object, but received: \${f(e)}\`,coercer:e=>d(e)?{...e}:e})}(r):I(r)}function w(e,t){return new h({type:e,schema:null,validator:t})}function S(e){let t;return new h({type:"lazy",schema:null,*entries(n,r){t??(t=e()),yield*t.entries(n,r)},validator:(n,r)=>(t??(t=e()),t.validator(n,r)),coercer:(n,r)=>(t??(t=e()),t.coercer(n,r)),refiner:(n,r)=>(t??(t=e()),t.refiner(n,r))})}function O(e){return new h({type:"array",schema:e,*entries(t){if(e&&Array.isArray(t))for(const[n,r]of t.entries())yield[n,r,e]},coercer:e=>Array.isArray(e)?e.slice():e,validator:e=>Array.isArray(e)||\`Expected an array value, but received: \${f(e)}\`})}function j(){return w("boolean",(e=>"boolean"==typeof e))}function N(e){const t=f(e),n=typeof e;return new h({type:"literal",schema:"string"===n||"number"===n||"boolean"===n?e:null,validator:n=>n===e||\`Expected the literal \\\`\${t}\\\`, but received: \${f(n)}\`})}function P(){return w("never",(()=>!1))}function x(e){return new h({...e,validator:(t,n)=>null===t||e.validator(t,n),refiner:(t,n)=>null===t||e.refiner(t,n)})}function A(){return w("number",(e=>"number"==typeof e&&!isNaN(e)||\`Expected a number, but received: \${f(e)}\`))}function I(e){const t=e?Object.keys(e):[],n=P();return new h({type:"object",schema:e??null,*entries(r){if(e&&d(r)){const o=new Set(Object.keys(r));for(const n of t)o.delete(n),yield[n,r[n],e[n]];for(const e of o)yield[e,r[e],n]}},validator:e=>d(e)||\`Expected an object, but received: \${f(e)}\`,coercer:e=>d(e)?{...e}:e})}function k(e){return new h({...e,validator:(t,n)=>void 0===t||e.validator(t,n),refiner:(t,n)=>void 0===t||e.refiner(t,n)})}function _(e,t){return new h({type:"record",schema:null,*entries(n){if(d(n))for(const r in n){const o=n[r];yield[r,r,e],yield[r,o,t]}},validator:e=>d(e)||\`Expected an object, but received: \${f(e)}\`})}function C(){return w("string",(e=>"string"==typeof e||\`Expected a string, but received: \${f(e)}\`))}function $(e){const t=e.map((e=>e.type)).join(" | ");return new h({type:"union",schema:null,coercer(t){for(const n of e){const[e,r]=n.validate(t,{coerce:!0});if(!e)return r}return t},validator(n,r){const o=[];for(const t of e){const[...e]=m(n,t,r),[i]=e;if(!i?.[0])return[];for(const[t]of e)t&&o.push(t)}return[\`Expected the value to satisfy a union of \\\`\${t}\\\`, but received: \${f(n)}\`,...o]}})}function J(e,t,n){return new h({...e,coercer:(r,o)=>g(r,t)?e.coercer(n(r,o),o):e.coercer(r,o)})}function T(e){return function(e){return function(e){return"object"==typeof e&&null!==e&&"message"in e}(e)&&"string"==typeof e.message?e.message:null==e?"":String(e)}(e).replace(/\\.$/u,"")}function R(e,t){return n=e,Boolean("string"==typeof n?.prototype?.constructor?.name)?new e({message:t}):e({message:t});var n}class F extends Error{constructor(e){super(e.message),this.code="ERR_ASSERTION"}}function q(e,t="Assertion failed.",n=F){if(!e){if(t instanceof Error)throw t;throw R(n,t)}}const L=e=>I(e);function M({path:e,branch:t}){const n=e[e.length-1];return s(t[t.length-2],n)}function U(e){return new h({...e,type:\`optional \${e.type}\`,validator:(t,n)=>!M(n)||e.validator(t,n),refiner:(t,n)=>!M(n)||e.refiner(t,n)})}const z=$([N(null),j(),w("finite number",(e=>g(e,A())&&Number.isFinite(e))),C(),O(S((()=>z))),_(C(),S((()=>z)))]),B=J(z,w("any",(()=>!0)),(e=>(function(e,t,n="Assertion failed",r=F){try{y(e,t)}catch(e){throw R(r,\`\${n}: \${T(e)}.\`)}}(e,z),JSON.parse(JSON.stringify(e,((e,t)=>{if("__proto__"!==e&&"constructor"!==e)return t}))))));function D(e){try{return function(e){v(e,B)}(e),!0}catch{return!1}}const X=N("2.0"),G=x($([A(),C()])),H=L({code:w("integer",(e=>"number"==typeof e&&!isNaN(e)&&Number.isInteger(e)||\`Expected an integer, but received: \${f(e)}\`)),message:C(),data:U(B),stack:U(C())}),Q=$([_(C(),B),O(B)]);L({id:G,jsonrpc:X,method:C(),params:U(Q)}),L({jsonrpc:X,method:C(),params:U(Q)});I({id:G,jsonrpc:X,result:k(w("unknown",(()=>!0))),error:k(H)});const W=L({id:G,jsonrpc:X,result:B}),K=L({id:G,jsonrpc:X,error:H});$([W,K]);var V=o.internal,Y="Unspecified error message. This is a bug, please report it.",Z=(ee(V),"Unspecified server error.");function ee(e,t=Y){if(function(e){return Number.isInteger(e)}(e)){const t=e.toString();if(s(i,t))return i[t].message;if(function(e){return e>=-32099&&e<=-32e3}(e))return Z}return t}function te(e){return Array.isArray(e)?e.map((e=>D(e)?e:a(e)?ne(e):null)):a(e)?ne(e):D(e)?e:null}function ne(e){return Object.getOwnPropertyNames(e).reduce(((t,n)=>{const r=e[n];return D(r)&&(t[n]=r),t}),{})}var re=n(12),oe=class extends Error{constructor(e,t,n){var r=(...e)=>{super(...e)};if(!Number.isInteger(e))throw new Error('"code" must be an integer.');if(!t||"string"!=typeof t)throw new Error('"message" must be a non-empty string.');!function(e){return a(e)&&s(e,"cause")&&a(e.cause)}(n)?r(t):(r(t,{cause:n.cause}),s(this,"cause")||Object.assign(this,{cause:n.cause})),void 0!==n&&(this.data=n),this.code=e}serialize(){const e={code:this.code,message:this.message};return void 0!==this.data&&(e.data=this.data,function(e){if("object"!=typeof e||null===e)return!1;try{let t=e;for(;null!==Object.getPrototypeOf(t);)t=Object.getPrototypeOf(t);return Object.getPrototypeOf(e)===t}catch(e){return!1}}(this.data)&&(e.data.cause=te(this.data.cause))),this.stack&&(e.stack=this.stack),e}toString(){return re(this.serialize(),ie,2)}};function ie(e,t){if("[Circular]"!==t)return t}var ae,se,ce=e=>ue(o.methodNotFound,e);function ue(e,t){const[n,r]=de(t);return new oe(e,n??ee(e),r)}function de(e){if(e){if("string"==typeof e)return[e];if("object"==typeof e&&!Array.isArray(e)){const{message:t,data:n}=e;if(t&&"string"!=typeof t)throw new Error("Must specify string message.");return[t??void 0,n]}}return[]}!function(e){e.Alert="alert",e.Confirmation="confirmation",e.Prompt="prompt"}(ae||(ae={})),function(e){e.ButtonClickEvent="ButtonClickEvent",e.FormSubmitEvent="FormSubmitEvent",e.InputChangeEvent="InputChangeEvent",e.FileUploadEvent="FileUploadEvent"}(se||(se={}));const fe=I({type:C(),name:k(C())}),le=E(fe,I({type:N(se.ButtonClickEvent),name:k(C())})),pe=I({name:C(),size:A(),contentType:C(),contents:C()}),me=E(fe,I({type:N(se.FormSubmitEvent),value:_(C(),x($([C(),pe,j()]))),name:C()})),he=E(fe,I({type:N(se.InputChangeEvent),name:C(),value:$([C(),j()])}));$([le,me,he,E(fe,I({type:N(se.FileUploadEvent),name:C(),file:x(pe)}))]);function ye(e){return Object.fromEntries(Object.entries(e).filter((([,e])=>void 0!==e)))}function ve(e){return t=>{const{key:n=null,...r}=t;return{type:e,props:ye(r),key:n}}}const ge=ve("Text"),be=ve("Bold"),Ee=ve("Box"),we=ve("Tooltip"),Se=ve("Card"),Oe=ve("Button"),je=()=>t(ge,{children:["Click the ",e(be,{children:"increment"})," button to increase the count."]}),Ne=({count:n})=>t(Ee,{children:[e(we,{content:e(je,{}),children:e(ge,{children:"Hover for explanation"})}),e(Se,{title:"Count",value:String(n)}),e(Oe,{name:"increment",children:"Increment"})]});async function Pe(){const e=await snap.request({method:"snap_manageState",params:{operation:"get"}});return e?(q("number"==typeof e.count,"Expected count to be a number."),e.count):0}const xe=async({request:t})=>{if("display"===t.method){const t=await Pe();return await snap.request({method:"snap_dialog",params:{type:ae.Alert,content:e(Ne,{count:t})}})}throw ce({data:{method:t.method}})},Ae=async({event:t,id:n})=>{q(t.type===se.ButtonClickEvent),q("increment"===t.name);const r=await async function(){const e={count:await Pe()+1};return await snap.request({method:"snap_manageState",params:{operation:"update",newState:e}}),e.count}();await snap.request({method:"snap_updateInterface",params:{id:n,ui:e(Ne,{count:r})}})}})();var o=exports;for(var i in r)o[i]=r[i];r.__esModule&&Object.defineProperty(o,"__esModule",{value:!0})})();"`, ); - expect(location.version).toBe(templateSnapVersion); + expect(location.version).toBe(exampleSnapVersion); }); it('fetches a package tarball directly without fetching the metadata when possible', async () => { - const { version: templateSnapVersion } = JSON.parse( - ( - await readFile(require.resolve('@metamask/template-snap/package.json')) - ).toString('utf8'), - ); - const customFetchMock = jest.fn(); customFetchMock.mockResolvedValue({ @@ -138,59 +134,70 @@ describe('NpmLocation', () => { createReadStream( path.resolve( __dirname, - `../../../test/fixtures/metamask-template-snap-${templateSnapVersion}.tgz`, + `../../../test/fixtures/metamask-jsx-example-snap-${exampleSnapVersion}.tgz`, ), ), ), } as any); - const tarballUrl = `https://registry.npmjs.org/@metamask/template-snap/-/template-snap-${templateSnapVersion}.tgz`; + const tarballUrl = `https://registry.npmjs.org/@metamask/jsx-example-snap/-/jsx-example-snap-${exampleSnapVersion}.tgz`; - const location = new NpmLocation(new URL('npm:@metamask/template-snap'), { - versionRange: templateSnapVersion, - fetch: customFetchMock as typeof fetch, - }); + const location = new NpmLocation( + new URL('npm:@metamask/jsx-example-snap'), + { + versionRange: exampleSnapVersion, + fetch: customFetchMock as typeof fetch, + }, + ); const manifest = await location.manifest(); const sourceCode = ( await location.fetch(manifest.result.source.location.npm.filePath) ).toString(); - assert(manifest.result.source.location.npm.iconPath); - const svgIcon = ( - await location.fetch(manifest.result.source.location.npm.iconPath) - ).toString(); expect(customFetchMock).toHaveBeenCalledTimes(1); expect(customFetchMock).toHaveBeenNthCalledWith(1, tarballUrl); - expect(manifest.result).toStrictEqual( - JSON.parse( - ( - await readFile( - require.resolve('@metamask/template-snap/snap.manifest.json'), - ) - ).toString('utf8'), - ), - ); - - expect(sourceCode).toStrictEqual( - ( - await readFile( - require.resolve('@metamask/template-snap/dist/bundle.js'), - ) - ).toString('utf8'), - ); + expect(manifest.result).toMatchInlineSnapshot(` + { + "description": "MetaMask example snap demonstrating the use of JSX for UI components.", + "initialPermissions": { + "endowment:rpc": { + "dapps": true, + }, + "snap_dialog": {}, + "snap_manageState": {}, + }, + "manifestVersion": "0.1", + "proposedName": "JSX Example Snap", + "repository": { + "type": "git", + "url": "https://github.com/MetaMask/snaps.git", + }, + "source": { + "location": { + "npm": { + "filePath": "dist/bundle.js", + "packageName": "@metamask/jsx-example-snap", + "registry": "https://registry.npmjs.org/", + }, + }, + "shasum": "3U9+Lvmmdc9JRmaHLcwGgi9lpnaj25joBF9+zXY4644=", + }, + "version": "1.2.1", + } + `); - expect(svgIcon?.startsWith('')).toBe( - true, + expect(sourceCode).toMatchInlineSnapshot( + `"(()=>{var e={12:e=>{e.exports=a,a.default=a,a.stable=d,a.stableStringify=d;var t="[...]",n="[Circular]",r=[],o=[];function i(){return{depthLimit:Number.MAX_SAFE_INTEGER,edgesLimit:Number.MAX_SAFE_INTEGER}}function a(e,t,n,a){var s;void 0===a&&(a=i()),c(e,"",0,[],void 0,0,a);try{s=0===o.length?JSON.stringify(e,t,n):JSON.stringify(e,l(t),n)}catch(e){return JSON.stringify("[unable to serialize, circular reference is too complex to analyze]")}finally{for(;0!==r.length;){var u=r.pop();4===u.length?Object.defineProperty(u[0],u[1],u[3]):u[0][u[1]]=u[2]}}return s}function s(e,t,n,i){var a=Object.getOwnPropertyDescriptor(i,n);void 0!==a.get?a.configurable?(Object.defineProperty(i,n,{value:e}),r.push([i,n,t,a])):o.push([t,n,e]):(i[n]=e,r.push([i,n,t]))}function c(e,r,o,i,a,u,d){var f;if(u+=1,"object"==typeof e&&null!==e){for(f=0;fd.depthLimit)return void s(t,e,r,a);if(void 0!==d.edgesLimit&&o+1>d.edgesLimit)return void s(t,e,r,a);if(i.push(e),Array.isArray(e))for(f=0;ft?1:0}function d(e,t,n,a){void 0===a&&(a=i());var s,c=f(e,"",0,[],void 0,0,a)||e;try{s=0===o.length?JSON.stringify(c,t,n):JSON.stringify(c,l(t),n)}catch(e){return JSON.stringify("[unable to serialize, circular reference is too complex to analyze]")}finally{for(;0!==r.length;){var u=r.pop();4===u.length?Object.defineProperty(u[0],u[1],u[3]):u[0][u[1]]=u[2]}}return s}function f(e,o,i,a,c,d,l){var p;if(d+=1,"object"==typeof e&&null!==e){for(p=0;pl.depthLimit)return void s(t,e,o,c);if(void 0!==l.edgesLimit&&i+1>l.edgesLimit)return void s(t,e,o,c);if(a.push(e),Array.isArray(e))for(p=0;p0)for(var r=0;r{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var r={};(()=>{"use strict";function e(e,t,n){if("string"==typeof e)throw new Error(\`An HTML element ("\${String(e)}") was used in a Snap component, which is not supported by Snaps UI. Please use one of the supported Snap components.\`);if(!e)throw new Error("A JSX fragment was used in a Snap component, which is not supported by Snaps UI. Please use one of the supported Snap components.");return e({...t,key:n})}function t(t,n,r){return e(t,n,r)}n.r(r),n.d(r,{onRpcRequest:()=>xe,onUserInput:()=>Ae});var o={invalidInput:-32e3,resourceNotFound:-32001,resourceUnavailable:-32002,transactionRejected:-32003,methodNotSupported:-32004,limitExceeded:-32005,parse:-32700,invalidRequest:-32600,methodNotFound:-32601,invalidParams:-32602,internal:-32603},i={"-32700":{standard:"JSON RPC 2.0",message:"Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text."},"-32600":{standard:"JSON RPC 2.0",message:"The JSON sent is not a valid Request object."},"-32601":{standard:"JSON RPC 2.0",message:"The method does not exist / is not available."},"-32602":{standard:"JSON RPC 2.0",message:"Invalid method parameter(s)."},"-32603":{standard:"JSON RPC 2.0",message:"Internal JSON-RPC error."},"-32000":{standard:"EIP-1474",message:"Invalid input."},"-32001":{standard:"EIP-1474",message:"Resource not found."},"-32002":{standard:"EIP-1474",message:"Resource unavailable."},"-32003":{standard:"EIP-1474",message:"Transaction rejected."},"-32004":{standard:"EIP-1474",message:"Method not supported."},"-32005":{standard:"EIP-1474",message:"Request limit exceeded."},4001:{standard:"EIP-1193",message:"User rejected the request."},4100:{standard:"EIP-1193",message:"The requested account and/or method has not been authorized by the user."},4200:{standard:"EIP-1193",message:"The requested method is not supported by this Ethereum provider."},4900:{standard:"EIP-1193",message:"The provider is disconnected from all chains."},4901:{standard:"EIP-1193",message:"The provider is disconnected from the specified chain."}};function a(e){return Boolean(e)&&"object"==typeof e&&!Array.isArray(e)}const s=(e,t)=>Object.hasOwnProperty.call(e,t);var c;!function(e){e[e.Null=4]="Null",e[e.Comma=1]="Comma",e[e.Wrapper=1]="Wrapper",e[e.True=4]="True",e[e.False=5]="False",e[e.Quote=1]="Quote",e[e.Colon=1]="Colon",e[e.Date=24]="Date"}(c=c||(c={}));class u extends TypeError{constructor(e,t){let n;const{message:r,explanation:o,...i}=e,{path:a}=e,s=0===a.length?r:\`At path: \${a.join(".")} -- \${r}\`;super(o??s),null!=o&&(this.cause=s),Object.assign(this,i),this.name=this.constructor.name,this.failures=()=>n??(n=[e,...t()])}}function d(e){return"object"==typeof e&&null!==e}function f(e){return"symbol"==typeof e?e.toString():"string"==typeof e?JSON.stringify(e):\`\${e}\`}function l(e,t,n,r){if(!0===e)return;!1===e?e={}:"string"==typeof e&&(e={message:e});const{path:o,branch:i}=t,{type:a}=n,{refinement:s,message:c=\`Expected a value of type \\\`\${a}\\\`\${s?\` with refinement \\\`\${s}\\\`\`:""}, but received: \\\`\${f(r)}\\\`\`}=e;return{value:r,type:a,refinement:s,key:o[o.length-1],path:o,branch:i,...e,message:c}}function*p(e,t,n,r){(function(e){return d(e)&&"function"==typeof e[Symbol.iterator]})(e)||(e=[e]);for(const o of e){const e=l(o,t,n,r);e&&(yield e)}}function*m(e,t,n={}){const{path:r=[],branch:o=[e],coerce:i=!1,mask:a=!1}=n,s={path:r,branch:o};if(i&&(e=t.coercer(e,s),a&&"type"!==t.type&&d(t.schema)&&d(e)&&!Array.isArray(e)))for(const n in e)void 0===t.schema[n]&&delete e[n];let c="valid";for(const r of t.validator(e,s))r.explanation=n.message,c="not_valid",yield[r,void 0];for(let[u,f,l]of t.entries(e,s)){const t=m(f,l,{path:void 0===u?r:[...r,u],branch:void 0===u?o:[...o,f],coerce:i,mask:a,message:n.message});for(const n of t)n[0]?(c=null===n[0].refinement||void 0===n[0].refinement?"not_valid":"not_refined",yield[n[0],void 0]):i&&(f=n[1],void 0===u?e=f:e instanceof Map?e.set(u,f):e instanceof Set?e.add(f):d(e)&&(void 0!==f||u in e)&&(e[u]=f))}if("not_valid"!==c)for(const r of t.refiner(e,s))r.explanation=n.message,c="not_refined",yield[r,void 0];"valid"===c&&(yield[void 0,e])}class h{constructor(e){const{type:t,schema:n,validator:r,refiner:o,coercer:i=(e=>e),entries:a=function*(){}}=e;this.type=t,this.schema=n,this.entries=a,this.coercer=i,this.validator=r?(e,t)=>p(r(e,t),t,this,e):()=>[],this.refiner=o?(e,t)=>p(o(e,t),t,this,e):()=>[]}assert(e,t){return y(e,this,t)}create(e,t){return v(e,this,t)}is(e){return g(e,this)}mask(e,t){return function(e,t,n){const r=b(e,t,{coerce:!0,mask:!0,message:n});if(r[0])throw r[0];return r[1]}(e,this,t)}validate(e,t={}){return b(e,this,t)}}function y(e,t,n){const r=b(e,t,{message:n});if(r[0])throw r[0]}function v(e,t,n){const r=b(e,t,{coerce:!0,message:n});if(r[0])throw r[0];return r[1]}function g(e,t){return!b(e,t)[0]}function b(e,t,n={}){const r=m(e,t,n),o=function(e){const{done:t,value:n}=e.next();return t?void 0:n}(r);if(o[0]){return[new u(o[0],(function*(){for(const e of r)e[0]&&(yield e[0])})),void 0]}return[void 0,o[1]]}function E(...e){const t="type"===e[0]?.type,n=e.map((({schema:e})=>e)),r=Object.assign({},...n);return t?function(e){const t=Object.keys(e);return new h({type:"type",schema:e,*entries(n){if(d(n))for(const r of t)yield[r,n[r],e[r]]},validator:e=>d(e)||\`Expected an object, but received: \${f(e)}\`,coercer:e=>d(e)?{...e}:e})}(r):I(r)}function w(e,t){return new h({type:e,schema:null,validator:t})}function S(e){let t;return new h({type:"lazy",schema:null,*entries(n,r){t??(t=e()),yield*t.entries(n,r)},validator:(n,r)=>(t??(t=e()),t.validator(n,r)),coercer:(n,r)=>(t??(t=e()),t.coercer(n,r)),refiner:(n,r)=>(t??(t=e()),t.refiner(n,r))})}function O(e){return new h({type:"array",schema:e,*entries(t){if(e&&Array.isArray(t))for(const[n,r]of t.entries())yield[n,r,e]},coercer:e=>Array.isArray(e)?e.slice():e,validator:e=>Array.isArray(e)||\`Expected an array value, but received: \${f(e)}\`})}function j(){return w("boolean",(e=>"boolean"==typeof e))}function N(e){const t=f(e),n=typeof e;return new h({type:"literal",schema:"string"===n||"number"===n||"boolean"===n?e:null,validator:n=>n===e||\`Expected the literal \\\`\${t}\\\`, but received: \${f(n)}\`})}function P(){return w("never",(()=>!1))}function x(e){return new h({...e,validator:(t,n)=>null===t||e.validator(t,n),refiner:(t,n)=>null===t||e.refiner(t,n)})}function A(){return w("number",(e=>"number"==typeof e&&!isNaN(e)||\`Expected a number, but received: \${f(e)}\`))}function I(e){const t=e?Object.keys(e):[],n=P();return new h({type:"object",schema:e??null,*entries(r){if(e&&d(r)){const o=new Set(Object.keys(r));for(const n of t)o.delete(n),yield[n,r[n],e[n]];for(const e of o)yield[e,r[e],n]}},validator:e=>d(e)||\`Expected an object, but received: \${f(e)}\`,coercer:e=>d(e)?{...e}:e})}function k(e){return new h({...e,validator:(t,n)=>void 0===t||e.validator(t,n),refiner:(t,n)=>void 0===t||e.refiner(t,n)})}function _(e,t){return new h({type:"record",schema:null,*entries(n){if(d(n))for(const r in n){const o=n[r];yield[r,r,e],yield[r,o,t]}},validator:e=>d(e)||\`Expected an object, but received: \${f(e)}\`})}function C(){return w("string",(e=>"string"==typeof e||\`Expected a string, but received: \${f(e)}\`))}function $(e){const t=e.map((e=>e.type)).join(" | ");return new h({type:"union",schema:null,coercer(t){for(const n of e){const[e,r]=n.validate(t,{coerce:!0});if(!e)return r}return t},validator(n,r){const o=[];for(const t of e){const[...e]=m(n,t,r),[i]=e;if(!i?.[0])return[];for(const[t]of e)t&&o.push(t)}return[\`Expected the value to satisfy a union of \\\`\${t}\\\`, but received: \${f(n)}\`,...o]}})}function J(e,t,n){return new h({...e,coercer:(r,o)=>g(r,t)?e.coercer(n(r,o),o):e.coercer(r,o)})}function T(e){return function(e){return function(e){return"object"==typeof e&&null!==e&&"message"in e}(e)&&"string"==typeof e.message?e.message:null==e?"":String(e)}(e).replace(/\\.$/u,"")}function R(e,t){return n=e,Boolean("string"==typeof n?.prototype?.constructor?.name)?new e({message:t}):e({message:t});var n}class F extends Error{constructor(e){super(e.message),this.code="ERR_ASSERTION"}}function q(e,t="Assertion failed.",n=F){if(!e){if(t instanceof Error)throw t;throw R(n,t)}}const L=e=>I(e);function M({path:e,branch:t}){const n=e[e.length-1];return s(t[t.length-2],n)}function U(e){return new h({...e,type:\`optional \${e.type}\`,validator:(t,n)=>!M(n)||e.validator(t,n),refiner:(t,n)=>!M(n)||e.refiner(t,n)})}const z=$([N(null),j(),w("finite number",(e=>g(e,A())&&Number.isFinite(e))),C(),O(S((()=>z))),_(C(),S((()=>z)))]),B=J(z,w("any",(()=>!0)),(e=>(function(e,t,n="Assertion failed",r=F){try{y(e,t)}catch(e){throw R(r,\`\${n}: \${T(e)}.\`)}}(e,z),JSON.parse(JSON.stringify(e,((e,t)=>{if("__proto__"!==e&&"constructor"!==e)return t}))))));function D(e){try{return function(e){v(e,B)}(e),!0}catch{return!1}}const X=N("2.0"),G=x($([A(),C()])),H=L({code:w("integer",(e=>"number"==typeof e&&!isNaN(e)&&Number.isInteger(e)||\`Expected an integer, but received: \${f(e)}\`)),message:C(),data:U(B),stack:U(C())}),Q=$([_(C(),B),O(B)]);L({id:G,jsonrpc:X,method:C(),params:U(Q)}),L({jsonrpc:X,method:C(),params:U(Q)});I({id:G,jsonrpc:X,result:k(w("unknown",(()=>!0))),error:k(H)});const W=L({id:G,jsonrpc:X,result:B}),K=L({id:G,jsonrpc:X,error:H});$([W,K]);var V=o.internal,Y="Unspecified error message. This is a bug, please report it.",Z=(ee(V),"Unspecified server error.");function ee(e,t=Y){if(function(e){return Number.isInteger(e)}(e)){const t=e.toString();if(s(i,t))return i[t].message;if(function(e){return e>=-32099&&e<=-32e3}(e))return Z}return t}function te(e){return Array.isArray(e)?e.map((e=>D(e)?e:a(e)?ne(e):null)):a(e)?ne(e):D(e)?e:null}function ne(e){return Object.getOwnPropertyNames(e).reduce(((t,n)=>{const r=e[n];return D(r)&&(t[n]=r),t}),{})}var re=n(12),oe=class extends Error{constructor(e,t,n){var r=(...e)=>{super(...e)};if(!Number.isInteger(e))throw new Error('"code" must be an integer.');if(!t||"string"!=typeof t)throw new Error('"message" must be a non-empty string.');!function(e){return a(e)&&s(e,"cause")&&a(e.cause)}(n)?r(t):(r(t,{cause:n.cause}),s(this,"cause")||Object.assign(this,{cause:n.cause})),void 0!==n&&(this.data=n),this.code=e}serialize(){const e={code:this.code,message:this.message};return void 0!==this.data&&(e.data=this.data,function(e){if("object"!=typeof e||null===e)return!1;try{let t=e;for(;null!==Object.getPrototypeOf(t);)t=Object.getPrototypeOf(t);return Object.getPrototypeOf(e)===t}catch(e){return!1}}(this.data)&&(e.data.cause=te(this.data.cause))),this.stack&&(e.stack=this.stack),e}toString(){return re(this.serialize(),ie,2)}};function ie(e,t){if("[Circular]"!==t)return t}var ae,se,ce=e=>ue(o.methodNotFound,e);function ue(e,t){const[n,r]=de(t);return new oe(e,n??ee(e),r)}function de(e){if(e){if("string"==typeof e)return[e];if("object"==typeof e&&!Array.isArray(e)){const{message:t,data:n}=e;if(t&&"string"!=typeof t)throw new Error("Must specify string message.");return[t??void 0,n]}}return[]}!function(e){e.Alert="alert",e.Confirmation="confirmation",e.Prompt="prompt"}(ae||(ae={})),function(e){e.ButtonClickEvent="ButtonClickEvent",e.FormSubmitEvent="FormSubmitEvent",e.InputChangeEvent="InputChangeEvent",e.FileUploadEvent="FileUploadEvent"}(se||(se={}));const fe=I({type:C(),name:k(C())}),le=E(fe,I({type:N(se.ButtonClickEvent),name:k(C())})),pe=I({name:C(),size:A(),contentType:C(),contents:C()}),me=E(fe,I({type:N(se.FormSubmitEvent),value:_(C(),x($([C(),pe,j()]))),name:C()})),he=E(fe,I({type:N(se.InputChangeEvent),name:C(),value:$([C(),j()])}));$([le,me,he,E(fe,I({type:N(se.FileUploadEvent),name:C(),file:x(pe)}))]);function ye(e){return Object.fromEntries(Object.entries(e).filter((([,e])=>void 0!==e)))}function ve(e){return t=>{const{key:n=null,...r}=t;return{type:e,props:ye(r),key:n}}}const ge=ve("Text"),be=ve("Bold"),Ee=ve("Box"),we=ve("Tooltip"),Se=ve("Card"),Oe=ve("Button"),je=()=>t(ge,{children:["Click the ",e(be,{children:"increment"})," button to increase the count."]}),Ne=({count:n})=>t(Ee,{children:[e(we,{content:e(je,{}),children:e(ge,{children:"Hover for explanation"})}),e(Se,{title:"Count",value:String(n)}),e(Oe,{name:"increment",children:"Increment"})]});async function Pe(){const e=await snap.request({method:"snap_manageState",params:{operation:"get"}});return e?(q("number"==typeof e.count,"Expected count to be a number."),e.count):0}const xe=async({request:t})=>{if("display"===t.method){const t=await Pe();return await snap.request({method:"snap_dialog",params:{type:ae.Alert,content:e(Ne,{count:t})}})}throw ce({data:{method:t.method}})},Ae=async({event:t,id:n})=>{q(t.type===se.ButtonClickEvent),q("increment"===t.name);const r=await async function(){const e={count:await Pe()+1};return await snap.request({method:"snap_manageState",params:{operation:"update",newState:e}}),e.count}();await snap.request({method:"snap_updateInterface",params:{id:n,ui:e(Ne,{count:r})}})}})();var o=exports;for(var i in r)o[i]=r[i];r.__esModule&&Object.defineProperty(o,"__esModule",{value:!0})})();"`, ); - expect(location.version).toBe(templateSnapVersion); + expect(location.version).toBe(exampleSnapVersion); }); it('throws if fetch fails', async () => { fetchMock.mockResponse(async () => ({ status: 404, body: 'Not found' })); - const location = new NpmLocation(new URL('npm:@metamask/template-snap')); + const location = new NpmLocation(new URL('npm:@metamask/jsx-example-snap')); await expect(location.manifest()).rejects.toThrow( 'Failed to fetch NPM registry entry. Status code: 404.', ); @@ -200,13 +207,7 @@ describe('NpmLocation', () => { }); it('throws if fetching the NPM tarball fails', async () => { - const { version: templateSnapVersion } = JSON.parse( - ( - await readFile(require.resolve('@metamask/template-snap/package.json')) - ).toString('utf8'), - ); - - const tarballRegistry = `https://registry.npmjs.org/@metamask/template-snap/-/template-snap-${templateSnapVersion}.tgz`; + const tarballRegistry = `https://registry.npmjs.org/@metamask/jsx-example-snap/-/template-snap-${exampleSnapVersion}.tgz`; const customFetchMock = jest.fn(); @@ -215,10 +216,10 @@ describe('NpmLocation', () => { ok: true, json: async () => ({ 'dist-tags': { - latest: templateSnapVersion, + latest: exampleSnapVersion, }, versions: { - [templateSnapVersion]: { + [exampleSnapVersion]: { dist: { // return npmjs.org registry here so that we can check overriding it with npmjs.cf works tarball: tarballRegistry, @@ -232,33 +233,30 @@ describe('NpmLocation', () => { body: null, } as any); - const location = new NpmLocation(new URL('npm:@metamask/template-snap'), { - versionRange: templateSnapVersion, - fetch: customFetchMock as typeof fetch, - }); + const location = new NpmLocation( + new URL('npm:@metamask/jsx-example-snap'), + { + versionRange: exampleSnapVersion, + fetch: customFetchMock as typeof fetch, + }, + ); await expect(location.manifest()).rejects.toThrow( - 'Failed to fetch tarball for package "@metamask/template-snap"', + 'Failed to fetch tarball for package "@metamask/jsx-example-snap"', ); }); it('throws if the NPM tarball URL is invalid', async () => { - const { version: templateSnapVersion } = JSON.parse( - ( - await readFile(require.resolve('@metamask/template-snap/package.json')) - ).toString('utf8'), - ); - const customFetchMock = jest.fn(); customFetchMock.mockResolvedValueOnce({ ok: true, json: async () => ({ 'dist-tags': { - latest: templateSnapVersion, + latest: exampleSnapVersion, }, versions: { - [templateSnapVersion]: { + [exampleSnapVersion]: { dist: { tarball: 'foo', }, @@ -267,13 +265,16 @@ describe('NpmLocation', () => { }), } as any); - const location = new NpmLocation(new URL('npm:@metamask/template-snap'), { - versionRange: '*' as SemVerRange, - fetch: customFetchMock as typeof fetch, - }); + const location = new NpmLocation( + new URL('npm:@metamask/jsx-example-snap'), + { + versionRange: '*' as SemVerRange, + fetch: customFetchMock as typeof fetch, + }, + ); await expect(location.manifest()).rejects.toThrow( - `Failed to find valid tarball URL in NPM metadata for package "@metamask/template-snap".`, + `Failed to find valid tarball URL in NPM metadata for package "@metamask/jsx-example-snap".`, ); }); @@ -281,7 +282,7 @@ describe('NpmLocation', () => { expect( () => new NpmLocation( - new URL('npm://registry.npmjs.cf/@metamask/template-snap'), + new URL('npm://registry.npmjs.cf/@metamask/jsx-example-snap'), ), ).toThrow( 'Custom NPM registries are disabled, tried to use "https://registry.npmjs.cf/"', diff --git a/packages/snaps-controllers/test/fixtures/metamask-jsx-example-snap-1.2.1.tgz b/packages/snaps-controllers/test/fixtures/metamask-jsx-example-snap-1.2.1.tgz new file mode 100644 index 0000000000000000000000000000000000000000..50cf4720afc253946503445d9d75657e335463e5 GIT binary patch literal 11962 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 b-~HL`(cN`--CcLrU-tSBwU?Mb08#(|kzjn2 diff --git a/yarn.lock b/yarn.lock index 6f420dc571..1658051c4e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4227,7 +4227,6 @@ __metadata: "@metamask/snaps-rpc-methods": "workspace:^" "@metamask/snaps-sdk": "workspace:^" "@metamask/snaps-utils": "workspace:^" - "@metamask/template-snap": "npm:^0.7.0" "@metamask/utils": "npm:^11.4.2" "@noble/hashes": "npm:^1.7.1" "@swc/core": "npm:1.11.31" @@ -4640,13 +4639,6 @@ __metadata: languageName: node linkType: hard -"@metamask/template-snap@npm:^0.7.0": - version: 0.7.0 - resolution: "@metamask/template-snap@npm:0.7.0" - checksum: 10/70f11ec66945be906c22ea9f66e39624e5f7b7ae6b1e913bf2067e3278ed71ebe63953bb89146dcf7add21fc0815b895076c82d8a2af396029f06d2381eeacf9 - languageName: node - linkType: hard - "@metamask/test-snaps@workspace:packages/test-snaps": version: 0.0.0-use.local resolution: "@metamask/test-snaps@workspace:packages/test-snaps" From a7148ba47de084519a85973c9a532dde8560c5a5 Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Mon, 11 Aug 2025 14:34:53 +0200 Subject: [PATCH 2/2] Fix typo --- packages/snaps-controllers/src/snaps/location/npm.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/snaps-controllers/src/snaps/location/npm.test.ts b/packages/snaps-controllers/src/snaps/location/npm.test.ts index a898b932ea..bc76fca936 100644 --- a/packages/snaps-controllers/src/snaps/location/npm.test.ts +++ b/packages/snaps-controllers/src/snaps/location/npm.test.ts @@ -207,7 +207,7 @@ describe('NpmLocation', () => { }); it('throws if fetching the NPM tarball fails', async () => { - const tarballRegistry = `https://registry.npmjs.org/@metamask/jsx-example-snap/-/template-snap-${exampleSnapVersion}.tgz`; + const tarballRegistry = `https://registry.npmjs.org/@metamask/jsx-example-snap/-/jsx-example-snap-${exampleSnapVersion}.tgz`; const customFetchMock = jest.fn();