From 3d8202ccb58bff7da61a090787e84829dc958bcc Mon Sep 17 00:00:00 2001 From: Akshay Sharma <42249933+akshaysharmajs@users.noreply.github.com> Date: Tue, 13 Jun 2023 18:18:33 -0400 Subject: [PATCH 1/4] RPC test setup --- packages/snap/tests/rpc-test.ts | 92 +++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 packages/snap/tests/rpc-test.ts diff --git a/packages/snap/tests/rpc-test.ts b/packages/snap/tests/rpc-test.ts new file mode 100644 index 0000000..694931e --- /dev/null +++ b/packages/snap/tests/rpc-test.ts @@ -0,0 +1,92 @@ +import test from 'ava'; +import { onRpcRequest } from '../src/index'; +import { Address, Addresses } from '../src/types/address' +import { Json, JsonRpcRequest } from '@metamask/utils'; + +class PassingOnRpcRequestTests{ + //Initialize Sample Address + address1: Address = { + name: "User1", + address: "0x123456", + chain_id: "1", + }; + + address2: Address = { + name: "User2", + address: "0xabcdef", + chain_id: "2", + }; + + //Initialize Sample Address Book + SampleAddresses = new Addresses([this.address1, this.address2]); + + // Mock the Metamask snap object and its request method + snapMock = { + request: (params: any) => { + if ( + params.method === "snap_manageState" && + params.params.operation === "get" + ) { + console.log("check") + return { + addresses: this.SampleAddresses.string(), + }; + } + + if ( + params.method === "snap_manageState" && + params.params.operation === "update" + ) { + // Modify the SampleAddresses and return true + this.SampleAddresses.addresses = JSON.parse( + params.params.newState.addresses + ); + return true; + } + }, + }; + + constructor() { + test.before(() => { + (globalThis as any).snap = this.snapMock; + }); + } + + //onRpcRequest function should handle the "getAddresses" case correctly + async caseGetAddresses(t: any){ + const origin = 'test-origin'; + // Define the JSON-RPC request variable{} + const method : Json = "addAddress" + + let request: JsonRpcRequest> = { + method: "getAddresses", + jsonrpc: '2.0', + id: null, + params: [] + }; + + let result = await onRpcRequest({ origin, request }); + + // Check that the correct result is returned + t.deepEqual(result, [ + { + address: "0x123456", + chain_id: "1", + name: "User1", + }, + { + address: "0xabcdef", + chain_id: "2", + name: "User2", + }, + ]); + } + +} + +const tests = new PassingOnRpcRequestTests(); + +test.serial("onRpcRequest Tests", async (t) => { + await tests.caseGetAddresses(t); + +}); From 97397112764a12ee9dea46c587b5b7d167b78632 Mon Sep 17 00:00:00 2001 From: Akshay Sharma <42249933+akshaysharmajs@users.noreply.github.com> Date: Wed, 14 Jun 2023 12:52:39 -0400 Subject: [PATCH 2/4] Add remaining rpc address tests --- packages/snap/src/index.ts | 8 +-- packages/snap/src/state.ts | 4 ++ packages/snap/tests/rpc-test.ts | 121 ++++++++++++++++++++++---------- 3 files changed, 92 insertions(+), 41 deletions(-) diff --git a/packages/snap/src/index.ts b/packages/snap/src/index.ts index 79a37c1..caa1ea4 100644 --- a/packages/snap/src/index.ts +++ b/packages/snap/src/index.ts @@ -2,7 +2,7 @@ import { OnRpcRequestHandler } from "@metamask/snaps-types"; import { panel, text } from "@metamask/snaps-ui"; import { initializeChains } from "./initialize"; import { Chains } from "./types/chains"; -import { Address, Addresses } from "./types/address" +import { Address, Addresses } from "./types/address"; import { ChainState, AddressState } from "./state"; /** @@ -60,9 +60,9 @@ export const onRpcRequest: OnRpcRequestHandler = async ({ request }) => { throw new Error("Invalid addAddress request"); } - let new_address : Address = JSON.parse(request.params.address); + let new_address: Address = JSON.parse(request.params.address); - return await AddressState.addAddress(new_address) + return await AddressState.addAddress(new_address); case "deleteAddress": // Delete an address from the address book in wallet state @@ -77,7 +77,7 @@ export const onRpcRequest: OnRpcRequestHandler = async ({ request }) => { throw new Error("Invalid addAddress request"); } - return await AddressState.removeAddress(request.params.chain_id) + return await AddressState.removeAddress(request.params.chain_id); case "getAddresses": // Get all addresses from the address book in wallet state diff --git a/packages/snap/src/state.ts b/packages/snap/src/state.ts index f185376..c5ed38a 100644 --- a/packages/snap/src/state.ts +++ b/packages/snap/src/state.ts @@ -225,6 +225,8 @@ export class AddressState { newState: { addresses: addresses.string() }, }, }); + + return true; } /** @@ -295,5 +297,7 @@ export class AddressState { newState: { addresses: addresses.string() }, }, }); + + return true; } } diff --git a/packages/snap/tests/rpc-test.ts b/packages/snap/tests/rpc-test.ts index 694931e..905162f 100644 --- a/packages/snap/tests/rpc-test.ts +++ b/packages/snap/tests/rpc-test.ts @@ -1,10 +1,11 @@ -import test from 'ava'; -import { onRpcRequest } from '../src/index'; -import { Address, Addresses } from '../src/types/address' -import { Json, JsonRpcRequest } from '@metamask/utils'; +import test from "ava"; +import { onRpcRequest } from "../src/index"; +import { Address, Addresses } from "../src/types/address"; +import { Json, JsonRpcRequest } from "@metamask/utils"; +import { boolean } from "superstruct"; -class PassingOnRpcRequestTests{ - //Initialize Sample Address +class PassingOnRpcRequestTests { + //Initialize Sample Address address1: Address = { name: "User1", address: "0x123456", @@ -27,7 +28,6 @@ class PassingOnRpcRequestTests{ params.method === "snap_manageState" && params.params.operation === "get" ) { - console.log("check") return { addresses: this.SampleAddresses.string(), }; @@ -41,6 +41,7 @@ class PassingOnRpcRequestTests{ this.SampleAddresses.addresses = JSON.parse( params.params.newState.addresses ); + return true; } }, @@ -52,41 +53,87 @@ class PassingOnRpcRequestTests{ }); } - //onRpcRequest function should handle the "getAddresses" case correctly - async caseGetAddresses(t: any){ - const origin = 'test-origin'; - // Define the JSON-RPC request variable{} - const method : Json = "addAddress" - - let request: JsonRpcRequest> = { - method: "getAddresses", - jsonrpc: '2.0', - id: null, - params: [] - }; - - let result = await onRpcRequest({ origin, request }); - - // Check that the correct result is returned - t.deepEqual(result, [ - { - address: "0x123456", - chain_id: "1", - name: "User1", - }, - { - address: "0xabcdef", - chain_id: "2", - name: "User2", - }, - ]); - } + //onRpcRequet function should handle the "addAddress" case correctly + async caseAddAddress(t: any) { + //Initialize new address + const new_address: Address = { + name: "User3", + address: "0x456789", + chain_id: "3", + }; + + const origin = "test-origin"; + + // Define the JSON-RPC request variable{} + let request: JsonRpcRequest> = { + method: "addAddress", + jsonrpc: "2.0", + id: null, + params: { + address: JSON.stringify(new_address), + }, + }; + + let result = await onRpcRequest({ origin, request }); + + // Check that the correct result is returned + t.deepEqual(result, true); + } + + //onRpcRequet function should handle the "deleteAddress" case correctly + async caseDeleteAddress(t: any) { + const origin = "test-origin"; + + // Define the JSON-RPC request variable{} + let request: JsonRpcRequest> = { + method: "deleteAddress", + jsonrpc: "2.0", + id: null, + params: { + chain_id: "3", + }, + }; + + let result = await onRpcRequest({ origin, request }); + + // Check that the correct result is returned + t.deepEqual(result, true); + } + + //onRpcRequest function should handle the "getAddresses" case correctly + async caseGetAddresses(t: any) { + const origin = "test-origin"; + // Define the JSON-RPC request variable{} + let request: JsonRpcRequest> = { + method: "getAddresses", + jsonrpc: "2.0", + id: null, + params: [], + }; + + let result = await onRpcRequest({ origin, request }); + + // Check that the correct result is returned + t.deepEqual(result, [ + { + address: "0x123456", + chain_id: "1", + name: "User1", + }, + { + address: "0xabcdef", + chain_id: "2", + name: "User2", + }, + ]); + } } const tests = new PassingOnRpcRequestTests(); test.serial("onRpcRequest Tests", async (t) => { await tests.caseGetAddresses(t); - + await tests.caseAddAddress(t); + await tests.caseDeleteAddress(t); }); From 86078829896e7198abcac4db8e5c77da874a8ee9 Mon Sep 17 00:00:00 2001 From: Akshay Sharma <42249933+akshaysharmajs@users.noreply.github.com> Date: Wed, 14 Jun 2023 16:11:43 -0400 Subject: [PATCH 3/4] Add failing test for AddressState methods --- packages/snap/tests/address-book-test.ts | 213 +++++++++++++++++------ 1 file changed, 159 insertions(+), 54 deletions(-) diff --git a/packages/snap/tests/address-book-test.ts b/packages/snap/tests/address-book-test.ts index b7854a9..7f8303c 100644 --- a/packages/snap/tests/address-book-test.ts +++ b/packages/snap/tests/address-book-test.ts @@ -3,53 +3,6 @@ import { AddressState } from "../src/state"; import { Addresses, Address } from "../src//types/address"; class PassingAddressStateTests { - //Initialize Sample Address - address1: Address = { - name: "User1", - address: "0x123456", - chain_id: "1", - }; - - address2: Address = { - name: "User2", - address: "0xabcdef", - chain_id: "2", - }; - - //Initialize Sample Address Book - SampleAddresses = new Addresses([this.address1, this.address2]); - - // Mock the Metamask snap object and its request method - snapMock = { - request: (params: any) => { - if ( - params.method === "snap_manageState" && - params.params.operation === "get" - ) { - return { - addresses: this.SampleAddresses.string(), - }; - } - - if ( - params.method === "snap_manageState" && - params.params.operation === "update" - ) { - // Modify the SampleAddresses and return true - this.SampleAddresses.addresses = JSON.parse( - params.params.newState.addresses - ); - return true; - } - }, - }; - - constructor() { - test.before(() => { - (globalThis as any).snap = this.snapMock; - }); - } - //getAddressBook function should return current state of address book async getAddressBookPassTest(t: any) { //get current state of AddressBook @@ -143,12 +96,164 @@ class PassingAddressStateTests { } } -const tests = new PassingAddressStateTests(); +class FailingAddressStateTests { + //getAddressBook function should throw error + async getAddressBookFailTest(t: any) { + await t.throwsAsync( + async () => { + await AddressState.getAddressBook(); + }, + { instanceOf: Error } + ); + } + + //getAddress function should throw error + async getAddressFailTest(t: any) { + await t.throwsAsync( + async () => { + await AddressState.getAddress("1"); + }, + { instanceOf: Error } + ); + } + + //addAddress function should throw error + async addAddressFailTest(t: any) { + //Initialize new address + const new_address: Address = { + name: "User4", + address: "0xghijkl", + chain_id: "4", + }; + + await t.throwsAsync( + async () => { + await AddressState.addAddress(new_address); + }, + { instanceOf: Error } + ); + } + + //removeAddress function should throw error + async removeAddressFailTest(t: any) { + await t.throwsAsync( + async () => { + await AddressState.removeAddress("1"); + }, + { instanceOf: Error } + ); + } + + //addAddresses function should throw error + async addAddressesFailTest(t: any) { + //Initialize new address + const new_address: Address = { + name: "User4", + address: "0xghijkl", + chain_id: "4", + }; + + //Initialize new address book + let new_address_book = new Addresses([new_address]); + + await t.throwsAsync( + async () => { + await AddressState.addAddresses(new_address_book); + }, + { instanceOf: Error } + ); + } +} + +//Intialize test classes +const passing_tests = new PassingAddressStateTests(); +const failing_tests = new FailingAddressStateTests(); + +test.serial("AddressState Passing Tests", async (t) => { + //Initialize Sample Address + const address1: Address = { + name: "User1", + address: "0x123456", + chain_id: "1", + }; + + const address2: Address = { + name: "User2", + address: "0xabcdef", + chain_id: "2", + }; + + //Initialize Sample Address Book + const SampleAddresses = new Addresses([address1, address2]); + + // Mock the Metamask snap object and its request method + const snapMock = { + request: (params: any) => { + if ( + params.method === "snap_manageState" && + params.params.operation === "get" + ) { + return { + addresses: SampleAddresses.string(), + }; + } + + if ( + params.method === "snap_manageState" && + params.params.operation === "update" + ) { + // Modify the SampleAddresses and return true + SampleAddresses.addresses = JSON.parse( + params.params.newState.addresses + ); + return true; + } + }, + }; + + (globalThis as any).snap = snapMock; + + await passing_tests.getAddressBookPassTest(t); + await passing_tests.getAddressPassTest(t); + await passing_tests.addAddressPassTest(t); + await passing_tests.removeAddressPassTest(t); + await passing_tests.addAddressesPassTest(t); +}); + +test.serial("AddressState Failing Tests", async (t) => { + // test data?.addresses == undefined + //Mock snap object + const snapMock1 = { + request: (params: any) => { + return { + addresses: undefined, + }; + }, + }; + + (globalThis as any).snap = snapMock1; + + await failing_tests.getAddressBookFailTest(t); + await failing_tests.getAddressFailTest(t); + await failing_tests.addAddressFailTest(t); + await failing_tests.removeAddressFailTest(t); + await failing_tests.addAddressesFailTest(t); + + // test typeof data?.addresses !== "string" + //Mock snap object + const snapMock2 = { + request: (params: any) => { + return { + addresses: 1, + }; + }, + }; + + (globalThis as any).snap = snapMock2; -test.serial("AddressState Tests", async (t) => { - await tests.getAddressBookPassTest(t); - await tests.getAddressPassTest(t); - await tests.addAddressPassTest(t); - await tests.removeAddressPassTest(t); - await tests.addAddressesPassTest(t); + await failing_tests.getAddressBookFailTest(t); + await failing_tests.getAddressFailTest(t); + await failing_tests.addAddressFailTest(t); + await failing_tests.removeAddressFailTest(t); + await failing_tests.addAddressesFailTest(t); }); From 235474b3182494ac78d1d0cb16cd9a3a607b177b Mon Sep 17 00:00:00 2001 From: Akshay Sharma <42249933+akshaysharmajs@users.noreply.github.com> Date: Thu, 15 Jun 2023 11:12:47 -0400 Subject: [PATCH 4/4] rpc failing tests and code refactoring --- packages/snap/tests/address-book-test.ts | 126 +++++++++++---------- packages/snap/tests/rpc-test.ts | 133 +++++++++++++++++++---- 2 files changed, 174 insertions(+), 85 deletions(-) diff --git a/packages/snap/tests/address-book-test.ts b/packages/snap/tests/address-book-test.ts index 7f8303c..7319235 100644 --- a/packages/snap/tests/address-book-test.ts +++ b/packages/snap/tests/address-book-test.ts @@ -3,6 +3,47 @@ import { AddressState } from "../src/state"; import { Addresses, Address } from "../src//types/address"; class PassingAddressStateTests { + //Initialize Sample Address + address1: Address = { + name: "User1", + address: "0x123456", + chain_id: "1", + }; + + address2: Address = { + name: "User2", + address: "0xabcdef", + chain_id: "2", + }; + + //Initialize Sample Address Book + SampleAddresses = new Addresses([this.address1, this.address2]); + + // Mock the Metamask snap object and its request method + snapMock = { + request: (params: any) => { + if ( + params.method === "snap_manageState" && + params.params.operation === "get" + ) { + return { + addresses: this.SampleAddresses.string(), + }; + } + + if ( + params.method === "snap_manageState" && + params.params.operation === "update" + ) { + // Modify the SampleAddresses and return true + this.SampleAddresses.addresses = JSON.parse( + params.params.newState.addresses + ); + return true; + } + }, + }; + //getAddressBook function should return current state of address book async getAddressBookPassTest(t: any) { //get current state of AddressBook @@ -97,6 +138,24 @@ class PassingAddressStateTests { } class FailingAddressStateTests { + //Mock snap object for 'data?.addresses == undefined' + snapMock1 = { + request: (params: any) => { + return { + addresses: undefined, + }; + }, + }; + + //Mock snap object for 'typeof data?.addresses !== "string"' + snapMock2 = { + request: (params: any) => { + return { + addresses: 1, + }; + }, + }; + //getAddressBook function should throw error async getAddressBookFailTest(t: any) { await t.throwsAsync( @@ -170,48 +229,7 @@ const passing_tests = new PassingAddressStateTests(); const failing_tests = new FailingAddressStateTests(); test.serial("AddressState Passing Tests", async (t) => { - //Initialize Sample Address - const address1: Address = { - name: "User1", - address: "0x123456", - chain_id: "1", - }; - - const address2: Address = { - name: "User2", - address: "0xabcdef", - chain_id: "2", - }; - - //Initialize Sample Address Book - const SampleAddresses = new Addresses([address1, address2]); - - // Mock the Metamask snap object and its request method - const snapMock = { - request: (params: any) => { - if ( - params.method === "snap_manageState" && - params.params.operation === "get" - ) { - return { - addresses: SampleAddresses.string(), - }; - } - - if ( - params.method === "snap_manageState" && - params.params.operation === "update" - ) { - // Modify the SampleAddresses and return true - SampleAddresses.addresses = JSON.parse( - params.params.newState.addresses - ); - return true; - } - }, - }; - - (globalThis as any).snap = snapMock; + (globalThis as any).snap = passing_tests.snapMock; await passing_tests.getAddressBookPassTest(t); await passing_tests.getAddressPassTest(t); @@ -221,17 +239,7 @@ test.serial("AddressState Passing Tests", async (t) => { }); test.serial("AddressState Failing Tests", async (t) => { - // test data?.addresses == undefined - //Mock snap object - const snapMock1 = { - request: (params: any) => { - return { - addresses: undefined, - }; - }, - }; - - (globalThis as any).snap = snapMock1; + (globalThis as any).snap = failing_tests.snapMock1; await failing_tests.getAddressBookFailTest(t); await failing_tests.getAddressFailTest(t); @@ -239,17 +247,7 @@ test.serial("AddressState Failing Tests", async (t) => { await failing_tests.removeAddressFailTest(t); await failing_tests.addAddressesFailTest(t); - // test typeof data?.addresses !== "string" - //Mock snap object - const snapMock2 = { - request: (params: any) => { - return { - addresses: 1, - }; - }, - }; - - (globalThis as any).snap = snapMock2; + (globalThis as any).snap = failing_tests.snapMock2; await failing_tests.getAddressBookFailTest(t); await failing_tests.getAddressFailTest(t); diff --git a/packages/snap/tests/rpc-test.ts b/packages/snap/tests/rpc-test.ts index 905162f..d1ca70d 100644 --- a/packages/snap/tests/rpc-test.ts +++ b/packages/snap/tests/rpc-test.ts @@ -2,7 +2,8 @@ import test from "ava"; import { onRpcRequest } from "../src/index"; import { Address, Addresses } from "../src/types/address"; import { Json, JsonRpcRequest } from "@metamask/utils"; -import { boolean } from "superstruct"; + +const origin = "test-origin"; class PassingOnRpcRequestTests { //Initialize Sample Address @@ -47,14 +48,8 @@ class PassingOnRpcRequestTests { }, }; - constructor() { - test.before(() => { - (globalThis as any).snap = this.snapMock; - }); - } - //onRpcRequet function should handle the "addAddress" case correctly - async caseAddAddress(t: any) { + async casePassAddAddress(t: any) { //Initialize new address const new_address: Address = { name: "User3", @@ -62,8 +57,6 @@ class PassingOnRpcRequestTests { chain_id: "3", }; - const origin = "test-origin"; - // Define the JSON-RPC request variable{} let request: JsonRpcRequest> = { method: "addAddress", @@ -81,9 +74,7 @@ class PassingOnRpcRequestTests { } //onRpcRequet function should handle the "deleteAddress" case correctly - async caseDeleteAddress(t: any) { - const origin = "test-origin"; - + async casePassDeleteAddress(t: any) { // Define the JSON-RPC request variable{} let request: JsonRpcRequest> = { method: "deleteAddress", @@ -101,9 +92,7 @@ class PassingOnRpcRequestTests { } //onRpcRequest function should handle the "getAddresses" case correctly - async caseGetAddresses(t: any) { - const origin = "test-origin"; - + async casePassGetAddresses(t: any) { // Define the JSON-RPC request variable{} let request: JsonRpcRequest> = { method: "getAddresses", @@ -130,10 +119,112 @@ class PassingOnRpcRequestTests { } } -const tests = new PassingOnRpcRequestTests(); +class FailingOnRpcRequestTests { + //Mock snap object for 'data?.addresses == undefined' + snapMock1 = { + request: (params: any) => { + return { + addresses: undefined, + }; + }, + }; + + //Mock snap object for 'typeof data?.addresses !== "string"' + snapMock2 = { + request: (params: any) => { + return { + addresses: 1, + }; + }, + }; + + //onRpcRequet function should throw error on "addAddress" case + async caseFailAddAddress(t: any) { + //Initialize new address + const new_address: Address = { + name: "User3", + address: "0x456789", + chain_id: "3", + }; + + // Define the JSON-RPC request variable{} + let request: JsonRpcRequest> = { + method: "addAddress", + jsonrpc: "2.0", + id: null, + params: { + address: JSON.stringify(new_address), + }, + }; + + await t.throwsAsync( + async () => { + await onRpcRequest({ origin, request }); + }, + { instanceOf: Error } + ); + } + + //onRpcRequet function should throw error on "deleteAddress" case + async caseFailDeleteAddress(t: any) { + // Define the JSON-RPC request variable{} + let request: JsonRpcRequest> = { + method: "deleteAddress", + jsonrpc: "2.0", + id: null, + params: { + chain_id: "3", + }, + }; + + await t.throwsAsync( + async () => { + await onRpcRequest({ origin, request }); + }, + { instanceOf: Error } + ); + } + + //onRpcRequest function should throw error on "getAddresses" case + async caseFailGetAddresses(t: any) { + // Define the JSON-RPC request variable{} + let request: JsonRpcRequest> = { + method: "getAddresses", + jsonrpc: "2.0", + id: null, + params: [], + }; + + await t.throwsAsync( + async () => { + await onRpcRequest({ origin, request }); + }, + { instanceOf: Error } + ); + } +} + +const passing_tests = new PassingOnRpcRequestTests(); +const failing_tests = new FailingOnRpcRequestTests(); + +test.serial("onRpcRequest Passing Tests", async (t) => { + (globalThis as any).snap = passing_tests.snapMock; + + await passing_tests.casePassGetAddresses(t); + await passing_tests.casePassAddAddress(t); + await passing_tests.casePassDeleteAddress(t); +}); + +test.serial("onRpcRequest Failing Tests", async (t) => { + (globalThis as any).snap = failing_tests.snapMock1; + + await failing_tests.caseFailGetAddresses(t); + await failing_tests.caseFailAddAddress(t); + await failing_tests.caseFailDeleteAddress(t); + + (globalThis as any).snap = failing_tests.snapMock2; -test.serial("onRpcRequest Tests", async (t) => { - await tests.caseGetAddresses(t); - await tests.caseAddAddress(t); - await tests.caseDeleteAddress(t); + await failing_tests.caseFailGetAddresses(t); + await failing_tests.caseFailAddAddress(t); + await failing_tests.caseFailDeleteAddress(t); });