From 378bf19c0530a7d6d78c5bb5183c594c4364d721 Mon Sep 17 00:00:00 2001 From: Peter <53189696+PeterYinusa@users.noreply.github.com> Date: Fri, 28 Jul 2023 09:59:12 -0400 Subject: [PATCH] JSON-RPC e2e test POC (#18213) * eth_call test * eth_chainId test * run json rpc tests * add ci job * remove query string param from url * eth_sendTransaction test * eth_sendTransaction test --------- Co-authored-by: Brad Decker --- .circleci/config.yml | 40 ++++++ package.json | 1 + test/e2e/json-rpc/eth_call.spec.js | 67 ++++++++++ test/e2e/json-rpc/eth_chainId.spec.js | 46 +++++++ test/e2e/json-rpc/eth_sendTransaction.spec.js | 121 ++++++++++++++++++ test/e2e/run-all.js | 9 +- 6 files changed, 283 insertions(+), 1 deletion(-) create mode 100644 test/e2e/json-rpc/eth_call.spec.js create mode 100644 test/e2e/json-rpc/eth_chainId.spec.js create mode 100644 test/e2e/json-rpc/eth_sendTransaction.spec.js diff --git a/.circleci/config.yml b/.circleci/config.yml index c8b82bc85..8b05dfcaa 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -147,6 +147,9 @@ workflows: - test-e2e-firefox: requires: - prep-build-test + - test-e2e-chrome-rpc: + requires: + - prep-build-test - test-e2e-chrome-snaps: requires: - prep-build-test-flask @@ -803,6 +806,43 @@ jobs: path: test-artifacts destination: test-artifacts + test-e2e-chrome-rpc: + executor: node-browsers + parallelism: 1 + steps: + - checkout + - run: + name: Re-Install Chrome + command: ./.circleci/scripts/chrome-install.sh + - attach_workspace: + at: . + - run: + name: Move test build to dist + command: mv ./dist-test ./dist + - run: + name: Move test zips to builds + command: mv ./builds-test ./builds + - run: + name: test:e2e:chrome:rpc + command: | + if .circleci/scripts/test-run-e2e.sh + then + yarn test:e2e:chrome:rpc --retries 2 + fi + no_output_timeout: 20m + - run: + name: Merge JUnit report + command: | + if [ "$(ls -A test/test-results/e2e)" ]; then + yarn test:e2e:report + fi + when: always + - store_artifacts: + path: test-artifacts + destination: test-artifacts + - store_test_results: + path: test/test-results/e2e.xml + test-e2e-firefox-snaps: executor: node-browsers parallelism: 4 diff --git a/package.json b/package.json index 380171a7b..a8cabd934 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "test:e2e:chrome": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js", "test:e2e:chrome:snaps": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js --snaps", "test:e2e:chrome:mv3": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js --mv3", + "test:e2e:chrome:rpc": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js --rpc", "test:e2e:firefox": "SELENIUM_BROWSER=firefox node test/e2e/run-all.js", "test:e2e:firefox:snaps": "SELENIUM_BROWSER=firefox node test/e2e/run-all.js --snaps", "test:e2e:single": "node test/e2e/run-e2e-test.js", diff --git a/test/e2e/json-rpc/eth_call.spec.js b/test/e2e/json-rpc/eth_call.spec.js new file mode 100644 index 000000000..592a298ff --- /dev/null +++ b/test/e2e/json-rpc/eth_call.spec.js @@ -0,0 +1,67 @@ +const { strict: assert } = require('assert'); +const { keccak256 } = require('@truffle/codec/dist/lib/evm/utils'); +const { convertToHexValue, withFixtures } = require('../helpers'); +const { SMART_CONTRACTS } = require('../seeder/smart-contracts'); +const FixtureBuilder = require('../fixture-builder'); + +describe('eth_call', function () { + const smartContract = SMART_CONTRACTS.NFTS; + const ganacheOptions = { + accounts: [ + { + secretKey: + '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', + balance: convertToHexValue(25000000000000000000), + }, + ], + }; + it('executes a new message call', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + ganacheOptions, + smartContract, + title: this.test.title, + }, + async ({ driver, _, contractRegistry }) => { + const contract = contractRegistry.getContractAddress(smartContract); + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + // eth_call + await driver.openNewPage(`http://127.0.0.1:8080`); + const balanceOf = `0x${keccak256('balanceOf(address)').toString( + 'hex', + )}`; + const walletAddress = '0x5cfe73b6021e818b776b421b1c4db2474086a7e1'; + const request = JSON.stringify({ + jsonrpc: '2.0', + method: 'eth_call', + params: [ + { + to: `${contract}`, + data: + `${balanceOf.slice(0, 10)}` + + '000000000000000000000000' + + `${walletAddress.substring(2)}`, + }, + 'latest', + ], + id: 0, + }); + const result = await driver.executeScript( + `return window.ethereum.request(${request})`, + ); + + assert.equal( + result, + '0x0000000000000000000000000000000000000000000000000000000000000001', + ); + }, + ); + }); +}); diff --git a/test/e2e/json-rpc/eth_chainId.spec.js b/test/e2e/json-rpc/eth_chainId.spec.js new file mode 100644 index 000000000..d86ccea60 --- /dev/null +++ b/test/e2e/json-rpc/eth_chainId.spec.js @@ -0,0 +1,46 @@ +const { strict: assert } = require('assert'); +const { convertToHexValue, withFixtures } = require('../helpers'); +const FixtureBuilder = require('../fixture-builder'); + +describe('eth_chainId', function () { + const ganacheOptions = { + accounts: [ + { + secretKey: + '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', + balance: convertToHexValue(25000000000000000000), + }, + ], + }; + it('returns the chain ID of the current network', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + ganacheOptions, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + // eth_chainId + await driver.openNewPage(`http://127.0.0.1:8080`); + const request = JSON.stringify({ + jsonrpc: '2.0', + method: 'eth_chainId', + params: [], + id: 0, + }); + const result = await driver.executeScript( + `return window.ethereum.request(${request})`, + ); + + assert.equal(result, '0x539'); + }, + ); + }); +}); diff --git a/test/e2e/json-rpc/eth_sendTransaction.spec.js b/test/e2e/json-rpc/eth_sendTransaction.spec.js new file mode 100644 index 000000000..90da37a4b --- /dev/null +++ b/test/e2e/json-rpc/eth_sendTransaction.spec.js @@ -0,0 +1,121 @@ +const { strict: assert } = require('assert'); +const { convertToHexValue, withFixtures } = require('../helpers'); +const FixtureBuilder = require('../fixture-builder'); + +describe('eth_sendTransaction', function () { + const ganacheOptions = { + hardfork: 'london', + accounts: [ + { + secretKey: + '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', + balance: convertToHexValue(25000000000000000000), + }, + ], + }; + const expectedHash = + '0x855951a65dcf5949dc54beb032adfb604c52a0a548a0f616799d6873a9521470'; + it('confirms a new transaction', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + ganacheOptions, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + // eth_sendTransaction + await driver.openNewPage(`http://127.0.0.1:8080`); + const request = JSON.stringify({ + jsonrpc: '2.0', + method: 'eth_sendTransaction', + params: [ + { + to: '0x5cfe73b6021e818b776b421b1c4db2474086a7e1', + from: '0x5cfe73b6021e818b776b421b1c4db2474086a7e1', + value: '0x0', + maxPriorityFeePerGas: '0x3b9aca00', + maxFeePerGas: '0x2540be400', + }, + ], + id: 0, + }); + await driver.executeScript( + `window.transactionHash = window.ethereum.request(${request})`, + ); + + // confirm transaction in mm popup + await driver.waitUntilXWindowHandles(3); + await driver.switchToWindowWithTitle('MetaMask Notification'); + await driver.clickElement({ text: 'Confirm', tag: 'button' }); + await driver.switchToWindowWithTitle('E2E Test Dapp'); + const actualHash = await driver.executeScript( + `return window.transactionHash;`, + ); + assert.equal(actualHash, expectedHash); + }, + ); + }); + it('rejects a new transaction', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + ganacheOptions, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + // eth_sendTransaction + await driver.openNewPage(`http://127.0.0.1:8080`); + const request = JSON.stringify({ + jsonrpc: '2.0', + method: 'eth_sendTransaction', + params: [ + { + to: '0x5cfe73b6021e818b776b421b1c4db2474086a7e1', + from: '0x5cfe73b6021e818b776b421b1c4db2474086a7e1', + value: '0x0', + maxPriorityFeePerGas: '0x3b9aca00', + maxFeePerGas: '0x2540be400', + }, + ], + id: 0, + }); + await driver.executeScript( + `window.transactionHash = window.ethereum.request(${request})`, + ); + + // reject transaction in mm popup + await driver.waitUntilXWindowHandles(3); + await driver.switchToWindowWithTitle('MetaMask Notification'); + await driver.clickElement({ text: 'Reject', tag: 'button' }); + await driver.switchToWindowWithTitle('E2E Test Dapp'); + const result = await driver + .executeScript(`return window.transactionHash;`) + .then((data) => { + return data; + }) + .catch((err) => { + return err; + }); + assert.ok( + result.message.includes( + 'MetaMask Tx Signature: User denied transaction signature.', + ), + ); + }, + ); + }); +}); diff --git a/test/e2e/run-all.js b/test/e2e/run-all.js index d045233e5..d97d6c8a1 100644 --- a/test/e2e/run-all.js +++ b/test/e2e/run-all.js @@ -50,6 +50,10 @@ async function main() { description: `run mv3 specific e2e tests`, type: 'boolean', }) + .option('rpc', { + description: `run json-rpc specific e2e tests`, + type: 'boolean', + }) .option('retries', { description: 'Set how many times the test should be retried upon failure.', @@ -59,13 +63,16 @@ async function main() { .strict() .help('help'); - const { browser, debug, retries, snaps, mv3 } = argv; + const { browser, debug, retries, snaps, mv3, rpc } = argv; let testPaths; if (snaps) { const testDir = path.join(__dirname, 'snaps'); testPaths = await getTestPathsForTestDir(testDir); + } else if (rpc) { + const testDir = path.join(__dirname, 'json-rpc'); + testPaths = await getTestPathsForTestDir(testDir); } else { const testDir = path.join(__dirname, 'tests'); testPaths = [