From 12943e0e71db83160c7465ee04a5a38f8872f02e Mon Sep 17 00:00:00 2001 From: PeterYinusa <53189696+PeterYinusa@users.noreply.github.com> Date: Tue, 9 Aug 2022 14:59:20 +0100 Subject: [PATCH] [E2E]: Set approval for all e2e (#15481) * Update test dapp * fix provider fix provider remove debug mint nft * Add collectibles spec Co-authored-by: Alex Donesky --- package.json | 2 +- test/e2e/ganache.js | 4 + test/e2e/helpers.js | 2 +- test/e2e/seeder/ganache-seeder.js | 41 +++--- test/e2e/seeder/smart-contracts.js | 19 ++- test/e2e/tests/collectibles.spec.js | 200 ++++++++++++++++++++++++++++ yarn.lock | 8 +- 7 files changed, 240 insertions(+), 36 deletions(-) create mode 100644 test/e2e/tests/collectibles.spec.js diff --git a/package.json b/package.json index 8b661526e..2b88f1a14 100644 --- a/package.json +++ b/package.json @@ -249,7 +249,7 @@ "@metamask/eslint-config-typescript": "^9.0.1", "@metamask/forwarder": "^1.1.0", "@metamask/phishing-warning": "^1.2.1", - "@metamask/test-dapp": "^5.1.1", + "@metamask/test-dapp": "^5.2.0", "@sentry/cli": "^1.58.0", "@storybook/addon-a11y": "^6.3.12", "@storybook/addon-actions": "^6.3.12", diff --git a/test/e2e/ganache.js b/test/e2e/ganache.js index 68950a79c..107b879ed 100644 --- a/test/e2e/ganache.js +++ b/test/e2e/ganache.js @@ -19,6 +19,10 @@ class Ganache { await this._server.listen(port); } + getProvider() { + return this._server.provider; + } + async quit() { if (!this._server) { throw new Error('Server not running yet'); diff --git a/test/e2e/helpers.js b/test/e2e/helpers.js index 6e1230a05..0763762c8 100644 --- a/test/e2e/helpers.js +++ b/test/e2e/helpers.js @@ -51,7 +51,7 @@ async function withFixtures(options, testSuite) { let contractRegistry; if (smartContract) { - const ganacheSeeder = new GanacheSeeder(true); + const ganacheSeeder = new GanacheSeeder(ganacheServer.getProvider()); await ganacheSeeder.deploySmartContract(smartContract); contractRegistry = ganacheSeeder.getContractRegistry(); } diff --git a/test/e2e/seeder/ganache-seeder.js b/test/e2e/seeder/ganache-seeder.js index 85cc199bc..0eaa7ae32 100644 --- a/test/e2e/seeder/ganache-seeder.js +++ b/test/e2e/seeder/ganache-seeder.js @@ -1,15 +1,14 @@ const { ethers } = require('ethers'); -const ganache = require('ganache'); -const { contractConfiguration } = require('./smart-contracts'); +const { SMART_CONTRACTS, contractConfiguration } = require('./smart-contracts'); const GanacheContractAddressRegistry = require('./ganache-contract-address-registry'); /* * Ganache seeder is used to seed initial smart contract or set initial blockchain state. */ class GanacheSeeder { - constructor(debug = false) { - this.debug = debug; + constructor(ganacheProvider) { this.smartContractRegistry = new GanacheContractAddressRegistry(); + this.ganacheProvider = ganacheProvider; } /** @@ -19,28 +18,26 @@ class GanacheSeeder { */ async deploySmartContract(contractName) { - if (this.debug) { - console.log('Deploying smart contracts using GanacheSeeder'); - } - const ethersProvider = new ethers.providers.Web3Provider( - ganache.provider(), + this.ganacheProvider, 'any', ); + const signer = ethersProvider.getSigner(); + const fromAddress = await signer.getAddress(); const contractFactory = new ethers.ContractFactory( contractConfiguration[contractName].abi, contractConfiguration[contractName].bytecode, - ethersProvider.getSigner(), + signer, ); let contract; - if (contractName === 'hst') { + if (contractName === SMART_CONTRACTS.HST) { contract = await contractFactory.deploy( - contractConfiguration.hst.initialAmount, - contractConfiguration.hst.tokenName, - contractConfiguration.hst.decimalUnits, - contractConfiguration.hst.tokenSymbol, + contractConfiguration[SMART_CONTRACTS.HST].initialAmount, + contractConfiguration[SMART_CONTRACTS.HST].tokenName, + contractConfiguration[SMART_CONTRACTS.HST].decimalUnits, + contractConfiguration[SMART_CONTRACTS.HST].tokenSymbol, ); } else { contract = await contractFactory.deploy(); @@ -48,10 +45,11 @@ class GanacheSeeder { await contract.deployTransaction.wait(); - if (this.debug) { - console.log( - `Contract mined! address: ${contract.address} transactionHash: ${contract.deployTransaction.hash}`, - ); + if (contractName === SMART_CONTRACTS.COLLECTIBLES) { + const transaction = await contract.mintCollectibles(1, { + from: fromAddress, + }); + await transaction.wait(); } this.storeSmartContractAddress(contractName, contract.address); } @@ -64,11 +62,6 @@ class GanacheSeeder { * @param contractAddress */ storeSmartContractAddress(contractName, contractAddress) { - if (this.debug) { - console.log( - `Storing smart contract address: [${contractName}] => ${contractAddress}`, - ); - } this.smartContractRegistry.storeNewContractAddress( contractName, contractAddress, diff --git a/test/e2e/seeder/smart-contracts.js b/test/e2e/seeder/smart-contracts.js index c2394bb9a..f7cc148c5 100644 --- a/test/e2e/seeder/smart-contracts.js +++ b/test/e2e/seeder/smart-contracts.js @@ -33,11 +33,18 @@ const failingContract = { abi: failingContractAbi, }; -const contractConfiguration = { - hst: hstFactory, - collectibles: collectiblesFactory, - piggybank: piggybankFactory, - failing: failingContract, +const SMART_CONTRACTS = { + HST: 'hst', + COLLECTIBLES: 'collectibles', + PIGGYBANK: 'piggybank', + FAILING: 'failing', }; -module.exports = { contractConfiguration }; +const contractConfiguration = { + [SMART_CONTRACTS.HST]: hstFactory, + [SMART_CONTRACTS.COLLECTIBLES]: collectiblesFactory, + [SMART_CONTRACTS.PIGGYBANK]: piggybankFactory, + [SMART_CONTRACTS.FAILING]: failingContract, +}; + +module.exports = { SMART_CONTRACTS, contractConfiguration }; diff --git a/test/e2e/tests/collectibles.spec.js b/test/e2e/tests/collectibles.spec.js new file mode 100644 index 000000000..53882d0a3 --- /dev/null +++ b/test/e2e/tests/collectibles.spec.js @@ -0,0 +1,200 @@ +const { strict: assert } = require('assert'); +const { + convertToHexValue, + withFixtures, + veryLargeDelayMs, +} = require('../helpers'); +const { SMART_CONTRACTS } = require('../seeder/smart-contracts'); + +describe('Collectibles', function () { + const smartContract = SMART_CONTRACTS.COLLECTIBLES; + const ganacheOptions = { + accounts: [ + { + secretKey: + '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', + balance: convertToHexValue(25000000000000000000), + }, + ], + }; + it('should transfer a single NFT from one account to another', async function () { + await withFixtures( + { + dapp: true, + fixtures: 'connected-state', + ganacheOptions, + smartContract, + title: this.test.title, + failOnConsoleError: false, + }, + 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); + + // Click transfer + await driver.openNewPage(`http://127.0.0.1:8080/?contract=${contract}`); + await driver.waitForSelector({ + css: '#collectiblesStatus', + text: 'Deployed', + }); + await driver.delay(veryLargeDelayMs); + await driver.fill('#transferTokenInput', '1'); + await driver.clickElement('#transferFromButton'); + await driver.waitUntilXWindowHandles(3); + const windowHandles = await driver.getAllWindowHandles(); + const extension = windowHandles[0]; + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + + // Confirm transfer + await driver.waitForSelector({ + css: '.confirm-page-container-summary__title', + text: 'TestDappCollectibles', + }); + await driver.clickElement({ text: 'Confirm', tag: 'button' }); + await driver.waitUntilXWindowHandles(2); + await driver.switchToWindow(extension); + await driver.clickElement('[data-testid="home__activity-tab"]'); + await driver.waitForSelector( + '.transaction-list__completed-transactions .transaction-list-item:nth-of-type(1)', + { timeout: 10000 }, + ); + + // Verify transaction + const completedTx = await driver.findElement('.list-item__title'); + const completedTxText = await completedTx.getText(); + assert.equal(completedTxText, 'Send Token'); + }, + ); + }); + it('should approve an address to transfer a single NFT', async function () { + await withFixtures( + { + dapp: true, + fixtures: 'connected-state', + ganacheOptions, + smartContract, + title: this.test.title, + failOnConsoleError: false, + }, + 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); + + // Click approve + await driver.openNewPage(`http://127.0.0.1:8080/?contract=${contract}`); + await driver.waitForSelector({ + css: '#collectiblesStatus', + text: 'Deployed', + }); + await driver.delay(veryLargeDelayMs); + await driver.fill('#approveTokenInput', '1'); + await driver.clickElement('#approveButton'); + await driver.waitUntilXWindowHandles(3); + const windowHandles = await driver.getAllWindowHandles(); + const extension = windowHandles[0]; + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + + // Verify dialog + const title = await driver.findElement( + '[data-testid="confirm-approve-title"]', + ); + const data = await driver.findElements( + '.confirm-approve-content__data .confirm-approve-content__small-text', + ); + assert.equal( + await title.getText(), + 'Give permission to access your TestDappCollectibles (#1)?', + ); + assert.equal(await data[0].getText(), 'Function: Approve'); + + // Confirm approval + await driver.clickElement({ text: 'Confirm', tag: 'button' }); + await driver.waitUntilXWindowHandles(2); + await driver.switchToWindow(extension); + await driver.clickElement('[data-testid="home__activity-tab"]'); + await driver.waitForSelector( + '.transaction-list__completed-transactions .transaction-list-item:nth-of-type(1)', + { timeout: 10000 }, + ); + + // Verify transaction + const completedTx = await driver.findElement('.list-item__title'); + const completedTxText = await completedTx.getText(); + assert.equal(completedTxText, 'Approve Token spend limit'); + }, + ); + }); + it('should approve an address to transfer all NFTs', async function () { + await withFixtures( + { + dapp: true, + fixtures: 'connected-state', + ganacheOptions, + smartContract, + title: this.test.title, + failOnConsoleError: false, + }, + 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); + + // Click set approval for all + await driver.openNewPage(`http://127.0.0.1:8080/?contract=${contract}`); + await driver.waitForSelector({ + css: '#collectiblesStatus', + text: 'Deployed', + }); + await driver.delay(veryLargeDelayMs); + await driver.clickElement('#setApprovalForAllButton'); + await driver.waitUntilXWindowHandles(3); + const windowHandles = await driver.getAllWindowHandles(); + const extension = windowHandles[0]; + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + + // Verify dialog + const title = await driver.findElement( + '[data-testid="confirm-approve-title"]', + ); + const data = await driver.findElements( + '.confirm-approve-content__data .confirm-approve-content__small-text', + ); + assert.equal( + await title.getText(), + 'Give permission to access all of your TestDappCollectibles?', + ); + assert.equal(await data[0].getText(), 'Function: SetApprovalForAll'); + assert.equal(await data[1].getText(), 'Parameters: true'); + + // Confirmation set approval for all + await driver.clickElement({ text: 'Confirm', tag: 'button' }); + await driver.waitUntilXWindowHandles(2); + await driver.switchToWindow(extension); + await driver.clickElement('[data-testid="home__activity-tab"]'); + await driver.waitForSelector( + '.transaction-list__completed-transactions .transaction-list-item:nth-of-type(1)', + { timeout: 10000 }, + ); + + // Verify transaction + const completedTx = await driver.findElement('.list-item__title'); + const completedTxText = await completedTx.getText(); + assert.equal(completedTxText, 'Approve Token with no spend limit'); + }, + ); + }); +}); diff --git a/yarn.lock b/yarn.lock index da88c99a7..1ca971087 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3174,10 +3174,10 @@ dependencies: "@metamask/controllers" "^30.0.0" -"@metamask/test-dapp@^5.1.1": - version "5.1.1" - resolved "https://registry.yarnpkg.com/@metamask/test-dapp/-/test-dapp-5.1.1.tgz#aadebf28542809650c57aa8f5a3489c748e1414f" - integrity sha512-Vast76cYR9vOvSH9Ut8y8LXZbDledUE2BkiLX+PGP5AOTp8Pn8V6jiYg1D/slBh7M8/Q/1AmdW9D0B+fw7esBQ== +"@metamask/test-dapp@^5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@metamask/test-dapp/-/test-dapp-5.2.0.tgz#ecae2525e7b4d5ef42b7f478b33e3a25152789f8" + integrity sha512-/1nUFm6kzYB0xigrLHc+yzkunnrUoqfnsiLs7eUD+Qfl2Qn5G6C9tIj9cgAx72lWVtqoo2vBTP+55ZW8lDroYw== "@metamask/types@^1.1.0": version "1.1.0"