diff --git a/cypress/e2e/claim-portal-failure.cy.ts b/cypress/e2e/claim-portal-failure.cy.ts index fa995fa8..76a50736 100644 --- a/cypress/e2e/claim-portal-failure.cy.ts +++ b/cypress/e2e/claim-portal-failure.cy.ts @@ -1,36 +1,89 @@ /* eslint-disable sonarjs/no-duplicate-string */ -import { JsonRpcProvider } from "@ethersproject/providers"; -import { Wallet } from "ethers"; +import { JsonRpcProvider, JsonRpcSigner } from "@ethersproject/providers"; + +const beneficiary = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"; + +/** + * MM is an extension and communicates with the page in a way that + * cannot be easily intercepted. For instance, calling `eth_accounts` + * via the wallet provider will not be intercepted, and any calls to the provider + * will be made directly to the provider and in the case of anvil we'll always + * have access to the signer without authentication. + * + * For this reason, it's kinda difficult to simulate failed transactions due + * to wallet provider issues as 1. Anvil will always succeed and 2. Returning + * a spoofed error causes the claim-loader to infite spin. This may be due to + * how the tests are structured or due to how errors are being handled in the portal. + * + * We are injecting the signer as a global variable to the window object + * which is applied in an error handler of connectWallet. + * + * This is a bit of a hack, but it's the only way to get a valid signer + * into the test env without having extensions installed. + * + */ describe("Claims Portal Failures", () => { - beforeEach(() => { - cy.clearAllCookies(); - cy.clearAllLocalStorage(); - cy.clearAllSessionStorage(); + describe("No connection to wallet provider", () => { + beforeEach(() => { + cy.clearAllCookies(); + cy.clearAllLocalStorage(); + cy.clearAllSessionStorage(); + + setupIntercepts(); + stubEthereum(beneficiary); + + cy.visit(`/${claimUrl}`); + cy.wait(2000); + }); + + it("should handle no connected signer", () => { + /** + * This covers a user declining to connect their wallet + */ + cy.get("#additionalDetails", { timeout: 15000 }).should("be.visible").invoke("click"); - setupIntercepts(); - setupBadStubs(); + cy.get("button[id='make-claim']").should("be.visible").click(); + cy.get("#invalidator").should("not.be.visible"); + cy.get("#claim-loader").should("not.be.visible"); + cy.get("#view-claim").should("not.be.visible").and("include.text", "View Claim"); - cy.visit(`/${claimUrl}`); - cy.wait(2000); + cy.get("body").should("contain.text", "This reward is not for you"); + }); }); - // need to simulate a failed tx response from the wallet signer -}); + describe("Failed transactions", () => { + const provider = new JsonRpcProvider("http://127.0.0.1:8545"); + const signer = provider.getSigner(); -function setupBadStubs(address?: string, signer?: Wallet, rpcUrl?: string) { - const provider = new JsonRpcProvider(rpcUrl); + beforeEach(() => { + cy.clearAllCookies(); + cy.clearAllLocalStorage(); + cy.clearAllSessionStorage(); - stubEthereum(address, signer); + setupIntercepts(); + stubEthereum(beneficiary, signer); - return { provider, signer }; -} + cy.visit(`/${claimUrl}`); + cy.wait(2000); + }); + + it("should handle feedback for a failed wallet provider transaction", () => { + cy.get("#additionalDetails", { timeout: 15000 }).should("be.visible").invoke("click"); + + cy.get("button[id='make-claim']").should("be.visible").click(); + cy.get("#claim-loader").should("be.visible"); + cy.get("#invalidator").should("not.be.visible"); + // cy.get("#claim-loader").should("not.be.visible"); // gets stuck here + }); + }); +}); function setupIntercepts() { cy.intercept("POST", "*", (req) => { // return a 404 for rpc optimization meaning no successful RPC // to return our balanceOf and allowance calls - if (req.body.method === "eth_getBlockByNumber") { + if (req.body.method == "eth_getBlockByNumber") { req.reply({ statusCode: 404, body: { @@ -43,6 +96,51 @@ function setupIntercepts() { }, }); } + + if (req.body.method == "eth_sendTransaction") { + req.reply({ + statusCode: 404, + body: { + jsonrpc: "2.0", + id: 44, + result: "0x", + }, + }); + } + + if (req.body.method == "eth_call") { + const selector = req.body.params[0].data.slice(0, 10); + + // balanceOf + if (selector == "0x70a08231") { + req.reply({ + statusCode: 200, + body: { + jsonrpc: "2.0", + id: 45, + result: "0x00000000000000000000000000000000000000000000478cf7610f95b9e70000", + }, + }); + } else if (selector == "0xdd62ed3e") { + // allowance + + req.reply({ + statusCode: 200, + body: { + jsonrpc: "2.0", + id: 46, + result: "0x0000000000000000000000000000000000c097ce7bc906e58377f59a8306ffff", + }, + }); + } else if (selector == "0x95d89b41" || selector == "0x313ce567" || selector == "0x4fe02b44") { + // decimals and symbol + // get names? + // nonceBitmap + } else if (selector == "0xcbf8b66c") { + // permit + // req.destroy(); + } + } }); cy.intercept("POST", "https://gnxgtwvmduxcwucovxqp.supabase.co/rest/v1/*", { @@ -59,93 +157,111 @@ function setupIntercepts() { }); } -function stubEthereum(address?: string, signer?: Wallet) { - // Stubbing the ethereum object +function stubEthereum(address?: string, signer?: JsonRpcSigner) { cy.on("window:before:load", (win) => { // eslint-disable-next-line @typescript-eslint/no-explicit-any ((win as any).ethereum = { isMetaMask: true, - enable: cy.stub().resolves([]), + enable: cy.stub().resolves([address]), request: cy.stub().callsFake(async (method) => { - if (method === "eth_requestAccounts") { - return []; + if (method == "eth_requestAccounts") { + return [address]; } - if (method === "wallet_sendDomainMetadata") { + if (method == "wallet_sendDomainMetadata") { return true; } - if (method === "wallet_addEthereumChain") { + if (method == "wallet_addEthereumChain") { return true; } - if (method === "wallet_switchEthereumChain") { + if (method == "wallet_switchEthereumChain") { return true; } - if (method === "wallet_watchAsset") { + if (method == "wallet_watchAsset") { return true; } - if (method === "eth_chainId") { + if (method == "eth_chainId") { return "0x7a69"; } - if (method === "eth_accounts") { - return []; + if (method == "eth_accounts") { + return [address]; } - if (method === "eth_signTypedData_v4") { - return ""; + if (method == "eth_signTypedData_v4") { + return "address"; } - if (method === "eth_estimateGas") { + if (method == "eth_estimateGas") { return "0x00"; } + + if (method == "eth_sendTransaction") { + return "0x"; + } + + if (method == "eth_call") { + return "0x"; + } }), on: cy.stub().callsFake((event, cb) => { - if (event === "accountsChanged") { + if (event == "accountsChanged") { // eslint-disable-next-line @typescript-eslint/no-explicit-any (win as any).ethereum.onAccountsChanged = cb; } }), autoRefreshOnNetworkChange: false, chainId: "0x7a69", - selectedAddress: "", - requestAccounts: cy.stub().resolves([]), + selectedAddress: address, + requestAccounts: cy.stub().resolves([address]), send: cy.stub().callsFake(async (method) => { - if (method === "eth_requestAccounts") { - return []; + if (method == "eth_requestAccounts") { + return [address]; } - if (method === "wallet_sendDomainMetadata") { + if (method == "wallet_sendDomainMetadata") { return true; } - if (method === "wallet_addEthereumChain") { + if (method == "wallet_addEthereumChain") { return true; } - if (method === "wallet_switchEthereumChain") { + if (method == "wallet_switchEthereumChain") { return true; } - if (method === "wallet_watchAsset") { + if (method == "wallet_watchAsset") { return true; } - if (method === "eth_chainId") { + if (method == "eth_chainId") { return "0x7a69"; } - if (method === "eth_accounts") { - return []; + if (method == "eth_accounts") { + return [address]; } - if (method === "eth_signTypedData_v4") { + if (method == "eth_signTypedData_v4") { return; } + + if (method == "eth_sendTransaction") { + return "0x"; + } + + if (method == "eth_call") { + return "0x"; + } + + if (method == "eth_estimateGas") { + return "0x00"; + } + + if (method == "wallet_watchAsset") { + return true; + } }), }), // eslint-disable-next-line @typescript-eslint/no-explicit-any - ((win as any).signer = signer - ? signer - : { - getAddress: () => address, - sendTransaction: cy.stub().resolves({ hash: "0x1234" }), - }); + signer ? ((win as any).signer = signer) : null; }); } // placed here due to length const claimUrl = - "?claim=W3sidHlwZSI6ImVyYzIwLXBlcm1pdCIsInBlcm1pdCI6eyJwZXJtaXR0ZWQiOnsidG9rZW4iOiIweGU5MUQxNTNFMGI0MTUxOEEyQ2U4RGQzRDc5NDRGYTg2MzQ2M2E5N2QiLCJhbW91bnQiOiIxMDAwMDAwMDAwMDAwMDAwMCJ9LCJub25jZSI6IjEwODc2OTM3ODM4MTQ4OTY1NTIxMDM2ODQ4NzgzNzgzMDA2MDU0MjAwMzcxOTM0NTY0MzYzMjQ5MDIzMTQ1MTcyOTczMTgzNDgwMTM5MiIsImRlYWRsaW5lIjoiMTE1NzkyMDg5MjM3MzE2MTk1NDIzNTcwOTg1MDA4Njg3OTA3ODUzMjY5OTg0NjY1NjQwNTY0MDM5NDU3NTg0MDA3OTEzMTI5NjM5OTM1In0sInRyYW5zZmVyRGV0YWlscyI6eyJ0byI6IjB4ZjM5RmQ2ZTUxYWFkODhGNkY0Y2U2YUI4ODI3Mjc5Y2ZmRmI5MjI2NiIsInJlcXVlc3RlZEFtb3VudCI6IjEwMDAwMDAwMDAwMDAwMDAwIn0sIm93bmVyIjoiMHg3MDk5Nzk3MEM1MTgxMmRjM0EwMTBDN2QwMWI1MGUwZDE3ZGM3OUM4Iiwic2lnbmF0dXJlIjoiMHg4YWZmYWU1ZTA5YTkyN2QwYjUzNDQ1M2Y4NTE5ZWVlZDE5MzY5MTBkZWFhOGY5YTA0OTM1ODQzNDMzNDA5NmExMTg5ZmVkM2MxNzgyZmU0ZGI5ZTNhMDg2NWVkYjc3ZDczYzliMDliOTgxMTBmN2Q0ZWEyY2Y5ZDBhM2Q1YjhjYzFjIiwibmV0d29ya0lkIjozMTMzN30seyJ0eXBlIjoiZXJjMjAtcGVybWl0IiwicGVybWl0Ijp7InBlcm1pdHRlZCI6eyJ0b2tlbiI6IjB4ZTkxRDE1M0UwYjQxNTE4QTJDZThEZDNENzk0NEZhODYzNDYzYTk3ZCIsImFtb3VudCI6IjkwMDAwMDAwMDAwMDAwMDAwMDAifSwibm9uY2UiOiI1NjQzNjc4ODI2MzUwOTQ3NTY2NzAwNzA4MDA5ODQ5MDM0MDE1OTExMzYxMjM5NTUyMTA3Mjk3NDkxNzcyNDA2Mzg0NDY2Mjc0NDEzMiIsImRlYWRsaW5lIjoiMTE1NzkyMDg5MjM3MzE2MTk1NDIzNTcwOTg1MDA4Njg3OTA3ODUzMjY5OTg0NjY1NjQwNTY0MDM5NDU3NTg0MDA3OTEzMTI5NjM5OTM1In0sInRyYW5zZmVyRGV0YWlscyI6eyJ0byI6IjB4ZjM5RmQ2ZTUxYWFkODhGNkY0Y2U2YUI4ODI3Mjc5Y2ZmRmI5MjI2NiIsInJlcXVlc3RlZEFtb3VudCI6IjkwMDAwMDAwMDAwMDAwMDAwMDAifSwib3duZXIiOiIweDcwOTk3OTcwQzUxODEyZGMzQTAxMEM3ZDAxYjUwZTBkMTdkYzc5QzgiLCJzaWduYXR1cmUiOiIweDhhZmZhZTVlMDlhOTI3ZDBiNTM0NDUzZjg1MTllZWVkMTkzNjkxMGRlYWE4ZjlhMDQ5MzU4NDM0MzM0MDk2YTExODlmZWQzYzE3ODJmZTRkYjllM2EwODY1ZWRiNzdkNzNjOWIwOWI5ODExMGY3ZDRlYTJjZjlkMGEzZDViOGNjMWMiLCJuZXR3b3JrSWQiOjMxMzM3fV0="; + "?claim=W3sidHlwZSI6ImVyYzIwLXBlcm1pdCIsInBlcm1pdCI6eyJwZXJtaXR0ZWQiOnsidG9rZW4iOiIweGU5MUQxNTNFMGI0MTUxOEEyQ2U4RGQzRDc5NDRGYTg2MzQ2M2E5N2QiLCJhbW91bnQiOiIxMDAwMDAwMDAwMDAwMDAwMCJ9LCJub25jZSI6IjExMTAwMTcxMzI2MzgxMjMwODc0NzIyNjQzODc5NzEyMzUyODY1MDc1NTE5OTAzNDE5OTg2MjExMjE4OTU2NTE5NzY5MDA2MTUwNjk4NiIsImRlYWRsaW5lIjoiMTE1NzkyMDg5MjM3MzE2MTk1NDIzNTcwOTg1MDA4Njg3OTA3ODUzMjY5OTg0NjY1NjQwNTY0MDM5NDU3NTg0MDA3OTEzMTI5NjM5OTM1In0sInRyYW5zZmVyRGV0YWlscyI6eyJ0byI6IjB4ZjM5RmQ2ZTUxYWFkODhGNkY0Y2U2YUI4ODI3Mjc5Y2ZmRmI5MjI2NiIsInJlcXVlc3RlZEFtb3VudCI6IjEwMDAwMDAwMDAwMDAwMDAwIn0sIm93bmVyIjoiMHg3MDk5Nzk3MEM1MTgxMmRjM0EwMTBDN2QwMWI1MGUwZDE3ZGM3OUM4Iiwic2lnbmF0dXJlIjoiMHg1M2U5Mzk4MjU5NmZkNGY5N2VmNTY5MDAzOGQwZjNlNmM0NTk3YzA0YjhiMDM2NDFiZGNkYjRjZWQzNzMxMTA3M2VlMmZlZTQ2MWZkMjI1MWNhYjFhMDIzMGJiNDY3N2UzM2UyNmJjMTUyNDZkMjZmOTFkY2YxZTdmOGI0Zjc1MzFjIiwibmV0d29ya0lkIjozMTMzN30seyJ0eXBlIjoiZXJjMjAtcGVybWl0IiwicGVybWl0Ijp7InBlcm1pdHRlZCI6eyJ0b2tlbiI6IjB4ZTkxRDE1M0UwYjQxNTE4QTJDZThEZDNENzk0NEZhODYzNDYzYTk3ZCIsImFtb3VudCI6IjkwMDAwMDAwMDAwMDAwMDAwMDAifSwibm9uY2UiOiIxMTM1Mjc0Mzk4NDkzOTE5OTY2NzU3OTAyNjg0MDUxOTk0NDkwODIxMzUzNzQxMjg4NzQ3ODcxNDQ0OTE0OTI5NzAwNjg4MDQ4ODM1MDciLCJkZWFkbGluZSI6IjExNTc5MjA4OTIzNzMxNjE5NTQyMzU3MDk4NTAwODY4NzkwNzg1MzI2OTk4NDY2NTY0MDU2NDAzOTQ1NzU4NDAwNzkxMzEyOTYzOTkzNSJ9LCJ0cmFuc2ZlckRldGFpbHMiOnsidG8iOiIweGYzOUZkNmU1MWFhZDg4RjZGNGNlNmFCODgyNzI3OWNmZkZiOTIyNjYiLCJyZXF1ZXN0ZWRBbW91bnQiOiI5MDAwMDAwMDAwMDAwMDAwMDAwIn0sIm93bmVyIjoiMHg3MDk5Nzk3MEM1MTgxMmRjM0EwMTBDN2QwMWI1MGUwZDE3ZGM3OUM4Iiwic2lnbmF0dXJlIjoiMHg1M2U5Mzk4MjU5NmZkNGY5N2VmNTY5MDAzOGQwZjNlNmM0NTk3YzA0YjhiMDM2NDFiZGNkYjRjZWQzNzMxMTA3M2VlMmZlZTQ2MWZkMjI1MWNhYjFhMDIzMGJiNDY3N2UzM2UyNmJjMTUyNDZkMjZmOTFkY2YxZTdmOGI0Zjc1MzFjIiwibmV0d29ya0lkIjozMTMzN31d"; // const freshPermit = // "?claim=W3sidHlwZSI6ImVyYzIwLXBlcm1pdCIsInBlcm1pdCI6eyJwZXJtaXR0ZWQiOnsidG9rZW4iOiIweGU5MUQxNTNFMGI0MTUxOEEyQ2U4RGQzRDc5NDRGYTg2MzQ2M2E5N2QiLCJhbW91bnQiOiIxMDAwMDAwMDAwMDAwMDAwMCJ9LCJub25jZSI6Ijg3NDg4NTI4MDI4NTg2Njg3NTA2NjEwOTc5NzI2ODQ5MjE0ODE2ODA1ODgwNDM5OTQwMjI5MTU3NTQyNDYyNTI3NTk1MTU2MjM2NzMiLCJkZWFkbGluZSI6IjExNTc5MjA4OTIzNzMxNjE5NTQyMzU3MDk4NTAwODY4NzkwNzg1MzI2OTk4NDY2NTY0MDU2NDAzOTQ1NzU4NDAwNzkxMzEyOTYzOTkzNSJ9LCJ0cmFuc2ZlckRldGFpbHMiOnsidG8iOiIweGYzOUZkNmU1MWFhZDg4RjZGNGNlNmFCODgyNzI3OWNmZkZiOTIyNjYiLCJyZXF1ZXN0ZWRBbW91bnQiOiIxMDAwMDAwMDAwMDAwMDAwMCJ9LCJvd25lciI6IjB4NzA5OTc5NzBDNTE4MTJkYzNBMDEwQzdkMDFiNTBlMGQxN2RjNzlDOCIsInNpZ25hdHVyZSI6IjB4OTdhYmVkYzUzYjJlMzAwZGI3ZWI0MjhjN2ZhNjUwYjZlMmE4NWExZGY1M2Q5ODYwMzhjMjNiZmRhMjRiOWFlMDVhMWQyNDZjYzIzZWE0YWY0YWE2ZmI4NmNiZTFiOGUxMWIyNDY2MTM5NGQxNjQwZDA4YTNhMWY5ZDgwMGJhMWUxYiIsIm5ldHdvcmtJZCI6MzEzMzd9LHsidHlwZSI6ImVyYzIwLXBlcm1pdCIsInBlcm1pdCI6eyJwZXJtaXR0ZWQiOnsidG9rZW4iOiIweGU5MUQxNTNFMGI0MTUxOEEyQ2U4RGQzRDc5NDRGYTg2MzQ2M2E5N2QiLCJhbW91bnQiOiI5MDAwMDAwMDAwMDAwMDAwMDAwIn0sIm5vbmNlIjoiNzk1MTcyNzkwODkwMzkxNjQzOTk1Mjc3OTc2MTU3MDIyMjk1NDgxOTIwMDQxNDA4NDM1MjMzODQwNTc1MTU0Njk5NjQ5MjEzMTE2NDUiLCJkZWFkbGluZSI6IjExNTc5MjA4OTIzNzMxNjE5NTQyMzU3MDk4NTAwODY4NzkwNzg1MzI2OTk4NDY2NTY0MDU2NDAzOTQ1NzU4NDAwNzkxMzEyOTYzOTkzNSJ9LCJ0cmFuc2ZlckRldGFpbHMiOnsidG8iOiIweGYzOUZkNmU1MWFhZDg4RjZGNGNlNmFCODgyNzI3OWNmZkZiOTIyNjYiLCJyZXF1ZXN0ZWRBbW91bnQiOiI5MDAwMDAwMDAwMDAwMDAwMDAwIn0sIm93bmVyIjoiMHg3MDk5Nzk3MEM1MTgxMmRjM0EwMTBDN2QwMWI1MGUwZDE3ZGM3OUM4Iiwic2lnbmF0dXJlIjoiMHg5N2FiZWRjNTNiMmUzMDBkYjdlYjQyOGM3ZmE2NTBiNmUyYTg1YTFkZjUzZDk4NjAzOGMyM2JmZGEyNGI5YWUwNWExZDI0NmNjMjNlYTRhZjRhYTZmYjg2Y2JlMWI4ZTExYjI0NjYxMzk0ZDE2NDBkMDhhM2ExZjlkODAwYmExZTFiIiwibmV0d29ya0lkIjozMTMzN31d"; diff --git a/cypress/e2e/claim-portal-non-web3.cy.ts b/cypress/e2e/claim-portal-non-web3.cy.ts index 77059289..f7adb8a9 100644 --- a/cypress/e2e/claim-portal-non-web3.cy.ts +++ b/cypress/e2e/claim-portal-non-web3.cy.ts @@ -1,5 +1,5 @@ /* eslint-disable sonarjs/no-duplicate-string */ -describe("Claims Portal Failures", () => { +describe("Claims Portal Non-Web3", () => { beforeEach(() => { cy.clearAllCookies(); cy.clearAllLocalStorage(); diff --git a/cypress/e2e/claim-portal-success.cy.ts b/cypress/e2e/claim-portal-success.cy.ts index c9b3394f..4c09f1b9 100644 --- a/cypress/e2e/claim-portal-success.cy.ts +++ b/cypress/e2e/claim-portal-success.cy.ts @@ -5,7 +5,7 @@ import { Wallet } from "ethers"; const beneficiary = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"; // anvil const SENDER_PRIVATE_KEY = "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"; // anvil -describe("Claims Portal", () => { +describe("Claims Portal Success", () => { beforeEach(() => { cy.clearAllCookies(); cy.clearAllLocalStorage(); diff --git a/cypress/scripts/anvil.ts b/cypress/scripts/anvil.ts index 83161445..d8c22635 100644 --- a/cypress/scripts/anvil.ts +++ b/cypress/scripts/anvil.ts @@ -11,7 +11,7 @@ setTimeout(() => { console.log(`\n\n Anvil setup complete \n\n`); }, 5000); -// anvil --chain-id 31337 --fork-url https://rpc.gnosis.gateway.fm --host 127.0.0.1 --port 8545 +// anvil --chain-id 31337 --fork-url https://eth.llamarpc.com --host 127.0.0.1 --port 8546 spawn("cast", ["rpc", "--rpc-url", url, "anvil_impersonateAccount", "0xba12222222228d8ba445958a75a0704d566bf2c8"], { stdio: "inherit",